/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.inspur.edp.lcm.metadata.core;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.inspur.edp.lcm.metadata.api.ConfigData.CommonConfigData;
import com.inspur.edp.lcm.metadata.api.ConfigData.MetadataConfiguration;
import com.inspur.edp.lcm.metadata.api.context.RefCommonContext;
import com.inspur.edp.lcm.metadata.api.entity.ExternalInfo;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.GspProject;
import com.inspur.edp.lcm.metadata.api.entity.Metadata4Ref;
import com.inspur.edp.lcm.metadata.api.entity.Metadata4RefDto;
import com.inspur.edp.lcm.metadata.api.entity.Metadata4RefForDB;
import com.inspur.edp.lcm.metadata.api.entity.MetadataCustomizationFilter;
import com.inspur.edp.lcm.metadata.api.entity.MetadataDto;
import com.inspur.edp.lcm.metadata.api.entity.MetadataFilter;
import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader;
import com.inspur.edp.lcm.metadata.api.entity.MetadataIndexItemDto;
import com.inspur.edp.lcm.metadata.api.entity.MetadataPackage;
import com.inspur.edp.lcm.metadata.api.entity.MetadataPackageHeader;
import com.inspur.edp.lcm.metadata.api.entity.MetadataPackageVersion;
import com.inspur.edp.lcm.metadata.api.entity.MetadataProject;
import com.inspur.edp.lcm.metadata.api.entity.MetadataReference;
import com.inspur.edp.lcm.metadata.api.entity.MetadataType;
import com.inspur.edp.lcm.metadata.api.entity.OperationEnum;
import com.inspur.edp.lcm.metadata.api.entity.Page;
import com.inspur.edp.lcm.metadata.api.entity.ProcessMode;
import com.inspur.edp.lcm.metadata.api.entity.ProjectHeader;
import com.inspur.edp.lcm.metadata.api.entity.ServiceUnitInfo;
import com.inspur.edp.lcm.metadata.api.entity.acrosssu.AcrossSUInfo;
import com.inspur.edp.lcm.metadata.api.entity.acrosssu.AcrossSUWhiteListConfiguration;
import com.inspur.edp.lcm.metadata.api.entity.metadataindex.LocalMetadataIndexItem;
import com.inspur.edp.lcm.metadata.api.entity.metadataindex.MetadataIndexDto;
import com.inspur.edp.lcm.metadata.api.entity.metadataindex.MetadataIndexRepoItemDto;
import com.inspur.edp.lcm.metadata.api.exception.ErrorCodes;
import com.inspur.edp.lcm.metadata.api.exception.LcmFileDevException;
import com.inspur.edp.lcm.metadata.api.exception.LcmMavenDevException;
import com.inspur.edp.lcm.metadata.api.exception.LcmMetadataDevException;
import com.inspur.edp.lcm.metadata.api.exception.LcmParseDevException;
import com.inspur.edp.lcm.metadata.api.exception.MetadataExceptionCode;
import com.inspur.edp.lcm.metadata.api.exception.MetadataNotFoundException;
import com.inspur.edp.lcm.metadata.api.i18n.LcmMetadataDevLog;
import com.inspur.edp.lcm.metadata.api.i18n.LogCodes;
import com.inspur.edp.lcm.metadata.api.mvnEntity.MavenPackageRefs;
import com.inspur.edp.lcm.metadata.api.mvnEntity.MetadataInfoFilter;
import com.inspur.edp.lcm.metadata.api.mvnEntity.MetadataInfoWithVersion;
import com.inspur.edp.lcm.metadata.api.mvnEntity.MetadataMavenInfo;
import com.inspur.edp.lcm.metadata.api.mvnEntity.PackageSourceDto;
import com.inspur.edp.lcm.metadata.api.mvnEntity.PageMetadataInfo;
import com.inspur.edp.lcm.metadata.api.mvnEntity.withprocessmode.MetadataInfoFilterWithProcessMode;
import com.inspur.edp.lcm.metadata.api.mvnEntity.withprocessmode.MetadataInfoWithVersionWithProcessMode;
import com.inspur.edp.lcm.metadata.api.mvnEntity.withprocessmode.MetadataMavenInfoWithProcessMode;
import com.inspur.edp.lcm.metadata.api.mvnEntity.withprocessmode.PageMetadataInfoWithProcessMode;
import com.inspur.edp.lcm.metadata.api.service.FileService;
import com.inspur.edp.lcm.metadata.api.service.MdpkgService;
import com.inspur.edp.lcm.metadata.api.service.MetadataRTService;
import com.inspur.edp.lcm.metadata.api.service.RefCommonService;
import com.inspur.edp.lcm.metadata.common.context.RuntimeContext;
import com.inspur.edp.metadata.rtcustomization.api.entity.Metadata4RefPageQueryParam;
import com.inspur.edp.metadata.rtcustomization.api.entity.Metadata4RefPageQueryResult;
import com.inspur.edp.metadata.service.dev.core.manager.MetadataInProjectManager;
import com.inspur.edp.lcm.metadata.common.FileServiceImp;
import com.inspur.edp.lcm.metadata.common.MetadataDtoConverter;
import com.inspur.edp.lcm.metadata.common.MetadataSerializer;
import com.inspur.edp.lcm.metadata.common.Utils;
import com.inspur.edp.lcm.metadata.common.configuration.ContentManagerHelper;
import com.inspur.edp.lcm.metadata.common.configuration.MavenSourceRuleHelper;
import com.inspur.edp.lcm.metadata.common.configuration.MetadataConfigurationHelper;
import com.inspur.edp.lcm.metadata.common.configuration.MetadataRefConfigHelper;
import com.inspur.edp.lcm.metadata.common.configuration.MetadataTypeHelper;
import com.inspur.edp.lcm.metadata.common.configuration.ReferenceManagerHelper;
import com.inspur.edp.lcm.metadata.common.util.AcrossSUWhiteListUtils;
import com.inspur.edp.lcm.metadata.common.util.ClassifierUtils;
import com.inspur.edp.lcm.metadata.common.util.PropertiesUtil;
import com.inspur.edp.lcm.metadata.core.domain.GspMdRecentUse;
import com.inspur.edp.lcm.metadata.core.entity.HashLinkedNodeMap;
import com.inspur.edp.lcm.metadata.core.entity.SourceType;
import com.inspur.edp.lcm.metadata.core.event.DirEventBroker;
import com.inspur.edp.lcm.metadata.core.event.MetadataCreateEventBroker;
import com.inspur.edp.lcm.metadata.core.event.MetadataEventBroker;
import com.inspur.edp.lcm.metadata.core.manager.IndexServerManager;
import com.inspur.edp.lcm.metadata.core.persistence.RepositoryFactory;
import com.inspur.edp.lcm.metadata.core.refi18n.IRefI18nFilter;
import com.inspur.edp.lcm.metadata.core.refi18n.RefI18nMetadataFactory;
import com.inspur.edp.lcm.metadata.core.util.MdpkgUtils;
import com.inspur.edp.lcm.metadata.devcommon.ManagerUtils;
import com.inspur.edp.lcm.metadata.inner.api.utils.IdeLogUtils;
import com.inspur.edp.lcm.metadata.spi.IMetadataReferenceManager;
import com.inspur.edp.lcm.metadata.spi.MetadataContentManager;
import com.inspur.edp.lcm.metadata.spi.event.DirEventArgs;
import com.inspur.edp.lcm.metadata.spi.event.MetadataEventArgs;
import com.inspur.edp.metadata.rtcustomization.api.CustomizationService;
import com.inspur.edp.metadata.rtcustomization.api.entity.Metadata4RefQueryParam;
import com.inspur.edp.metadata.rtcustomization.api.entity.MetadataScopeEnum;
import com.inspur.edp.metadata.rtcustomization.api.entity.SourceTypeEnum;
import com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationRtServerService;
import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.databaseobject.api.entity.AbstractDatabaseObject;
import io.iec.edp.caf.databaseobject.api.service.IDatabaseObjectService;
import io.iec.edp.caf.sysmanager.api.data.user.User;
import io.iec.edp.caf.sysmanager.api.manager.user.UserManager;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

/**
 * @author zhaoleitr
 */
@Slf4j
public class MetadataCoreManager {
    public static ThreadLocal<String> devRootPath = new ThreadLocal<>();
    private static final String METADATAINBO_INDEX_FILENAME = "metadatainboindex";
    private static final String IDE_FOLDERNAME = ".ide";
    private static final String PACKAGE_VERSION = "m0.1.0-SNAPSHOT";
    private static final String METADATA_BIN_PATH = FileServiceImp.combinePath(Utils.getMetadataProjPath(),Utils.getMetadataBinPath());
    private static final Lock lock = new ReentrantLock();
    private static MetadataCoreManager current;
    private final FileServiceImp fileService = new FileServiceImp();
    private final MetadataProjectCoreService metadataProjectCoreService = new MetadataProjectCoreService();
    private final GspProjectCoreService gspProjectCoreService = new GspProjectCoreService();
    private final PackageCoreService packageCoreService = new PackageCoreService();
    private final RefCommonService refCommonService = SpringBeanUtils.getBean(RefCommonService.class);
    private final IDatabaseObjectService databaseObjectService = SpringBeanUtils.getBean(IDatabaseObjectService.class);
    private MetadataRTService metadataRTService;
    private MdRecentUseService mdRecentUseService;
    private CustomizationService customizationService;
    private UserManager userManager;

    private CustomizationRtServerService customizationRtServerService;

    public static MetadataCoreManager getCurrent() {
        if (current == null) {
            current = new MetadataCoreManager();
        }
        return current;
    }
    private MdRecentUseService getMdRecentUseService() {
        if (mdRecentUseService == null) {
            mdRecentUseService = SpringBeanUtils.getBean(MdRecentUseService.class);
        }
        return mdRecentUseService;
    }

    private UserManager getUserManager() {
        if (userManager == null) {
            userManager = SpringBeanUtils.getBean(UserManager.class);
        }
        return userManager;
    }

    private MetadataRTService getMetadataRTService() {
        if (Objects.isNull(metadataRTService)) {
            metadataRTService = SpringBeanUtils.getBean(MetadataRTService.class);
        }
        return metadataRTService;
    }
    private CustomizationService getCustomizationService() {
        if (Objects.isNull(customizationService)) {
            customizationService = SpringBeanUtils.getBean(CustomizationService.class);
        }
        return customizationService;
    }
    private CustomizationRtServerService getCustomizationRtServerService() {
        if (Objects.isNull(customizationRtServerService)) {
            customizationRtServerService = SpringBeanUtils.getBean(CustomizationRtServerService.class);
        }
        return customizationRtServerService;
    }

    public void initializeMetadataEntity(GspMetadata metadata) {
        metadata.getHeader().setId(UUID.randomUUID().toString());
        MetadataContentManager manager = ContentManagerHelper.getInstance().getManager(metadata.getHeader().getType());
        if (manager != null) {
            manager.build(metadata);
        }
    }

    public void createMetadata(String absolutePath, GspMetadata metadata) {
        if (metadata.getHeader().getCode().length() > 128) {
            throw new LcmMetadataDevException(ErrorCodes.ECP_METADATA_DEV_0009);
        }
        // 元数据名称
        String suffix = MetadataTypeHelper.getInstance().getMetadataType(metadata.getHeader().getType()).getPostfix();
        String metadataFileName = metadata.getHeader().getCode() + suffix;
        String metadataFilePath = fileService.getCombinePath(absolutePath, metadataFileName);
        if (isMetadataExist(metadataFilePath)) {
            throw new LcmMetadataDevException(ErrorCodes.ECP_METADATA_DEV_0010, absolutePath, metadataFileName);
        }

        // 组装依赖
        buildMetadataRef(metadata);

        // 事件准备
        MetadataCreateEventBroker broker = SpringBeanUtils.getBean(MetadataCreateEventBroker.class);
        MetadataEventArgs args = new MetadataEventArgs(absolutePath, metadata);

        // 2. 保存前事件
        broker.fireMetadataCreatingEvent(args);

        String metadataStr = new MetadataSerializer().serialize(metadata);
        RepositoryFactory.getInstance().getMetadataRepository().save(metadataFilePath, metadataStr);

        // 4. 保存后事件
        args.setMetadataStr(metadataStr);
        broker.fireMetadataCreatedEvent(args);
    }

    public void saveMetadata(GspMetadata metadata, String path) {
        String dirPath = new File(path).getParent();

        // 设置上下文路径
        Utils.setMetadataPath(dirPath);

        // 1. 组装元数据依赖关系节点
        buildMetadataRef(metadata);

        // 事件准备
        MetadataEventBroker broker = SpringBeanUtils.getBean(MetadataEventBroker.class);
        MetadataEventArgs args = new MetadataEventArgs(path, metadata);

        // 2. 保存前事件
        broker.fireMetadataSavingEvent(args);

        // 获取元数据的配置信息
        MetadataConfiguration metadataConfiguration = MetadataConfigurationHelper.getInstance().getMetadataConfigurationData(metadata.getHeader().getType());
        CommonConfigData commonData = metadataConfiguration.getCommon();
        // 资源元数据
        I18nCoreService i18nCoreService = new I18nCoreService();
        if (i18nCoreService.isI18nMetadata(metadata)) {
            GspMetadata resourceMetadata = i18nCoreService.extractResourceMetadata(metadata, path);
            i18nCoreService.extractLanguageMetadata(metadata, resourceMetadata, path);
            return;
        }

        // 普通元数据需要抽取资源元数据
        if (commonData.getIsCreatingResourceMetadata() && !i18nCoreService.isI18nMetadata(metadata)) {
            i18nCoreService.extractResourceMetadata(metadata, path);
        }

        // 检查文件内容是否变化，如果未发生变化，则不进行保存
        String metadataStr = new MetadataSerializer().serialize(metadata);
        boolean contentChanged = metadataProjectCoreService.isContentChanged(path, metadataStr, OperationEnum.METADATA_SAVE);
        if (!contentChanged) {
            return;
        }

        // 3. 把元数据保存到文件
        RepositoryFactory.getInstance().getMetadataRepository().save(path, metadataStr);

        // 4. 保存后事件
        args.setMetadataStr(metadataStr);
        broker.fireMetadataSavedEvent(args);
    }

    public GspMetadata loadMetadata(String metadataFileName, String absolutePath) {
        String metadataPath = fileService.getCombinePath(absolutePath, metadataFileName);
        return loadMetadata(metadataPath);
    }

    public GspMetadata loadMetadata(String absolutePath) {
        GspMetadata metadata;
        if (!isMetadataExist(absolutePath)) {
            String relativePath = ManagerUtils.getRelativePath(absolutePath);
            throw new MetadataNotFoundException("Lcm", MetadataExceptionCode.METADATA_PATH_IS_INVALID, String.format("找不到元数据，元数据路径为：%s", relativePath), null);
        }
        try {
            RefCommonContext.setInvokeAtDesignTime(true);
            metadata = RepositoryFactory.getInstance().getMetadataRepository().load(absolutePath);
        } catch (Exception e) {
            throw new LcmMetadataDevException(e, ErrorCodes.ECP_METADATA_DEV_0011, absolutePath);
        } finally {
            RefCommonContext.setInvokeAtDesignTime(false);
        }

        if (metadata != null) {
            MetadataEventBroker broker = SpringBeanUtils.getBean(MetadataEventBroker.class);
            MetadataEventArgs args = new MetadataEventArgs();
            args.setMetadata(metadata);
            args.setPath(absolutePath);
            broker.fireMetadataAchievedEvent(args);
        }

        return metadata;
    }

    public GspMetadata loadMetadataByMetadataId(String metadataId, String absolutePath) {
        final List<GspMetadata> metadataList = getMetadataList(absolutePath);
        GspMetadata metadata = metadataList.stream().filter(md -> md.getHeader().getId().equals(metadataId)).findFirst().orElse(null);
        Utils.checkNPE(metadata, "工程" + absolutePath + "中找不到元数据" + metadataId);
        return getI18nMetadata(metadata.getHeader().getFileName(), metadata.getRelativePath(), RuntimeContext.getLanguage());
    }

    public GspMetadata loadMetadataInBo(String absoluteMetadataPath, String absoluteProjPath) {
        absoluteProjPath = metadataProjectCoreService.getProjPath(absoluteProjPath);
        GspProject currentGspProjectInfo = gspProjectCoreService.getGspProjectInfo(absoluteProjPath);
        GspProject metadataGspProjectInfo = gspProjectCoreService.getGspProjectInfo(absoluteMetadataPath);
        if (!currentGspProjectInfo.getMetadataPackageName().equals(metadataGspProjectInfo.getMetadataPackageName())) {
            updateBoRef(metadataGspProjectInfo, absoluteMetadataPath, absoluteProjPath);
        }
        File file = new File(absoluteMetadataPath);
        return loadMetadata(file.getName(), file.getParent());
    }

    private void updateBoRef(GspProject gspProjInfo, String metadataFullPath, String currentProjPath) {
        String projectPath = Paths.get("..").resolve(gspProjInfo.getMetadataProjectName().toLowerCase()).toString();

        updateRef(gspProjInfo, metadataFullPath, currentProjPath, projectPath);
    }

    /**
     * 更新元数据依赖
     * @param gspProjInfo 当前元数据工程
     * @param metadataFullPath 元数据绝对路径
     * @param currentProjPath 元数据工程路径
     * @param projectPath 引用工程相对路径
     */
    private void updateRef(GspProject gspProjInfo, String metadataFullPath, String currentProjPath, String projectPath) {
        ProjectHeader projectHeader = new ProjectHeader();
        projectHeader.setName(gspProjInfo.getMetadataPackageName());
        projectHeader.setProjectPath(projectPath);

        MetadataProject currentMetadataProject = metadataProjectCoreService.getMetadataProjInfo(currentProjPath);
        // 更新projectRefs前先执行循环引用检查
        checkCircle(currentProjPath, currentMetadataProject, projectHeader);

        updateProjectReference(currentProjPath, currentMetadataProject, projectHeader);

        MetadataProject metadataProject = metadataProjectCoreService.getMetadataProjInfo(metadataFullPath);
        metadataProjectCoreService.updateRefs(currentProjPath, currentMetadataProject, metadataProject.getMetadataPackageInfo());

        MavenPackageRefs gaByMdpkgName = MdpkgUtils.getGAWithApi(gspProjInfo.getMetadataPackageName(), gspProjInfo.getPackagePrefix());
        String groupId = gaByMdpkgName.getGroupId();
        String artifactId = gaByMdpkgName.getArtifactId();

        updateMavenReference(currentProjPath, groupId, artifactId, gspProjInfo.getMetadataPackageName(), PACKAGE_VERSION);
    }

    private void updateMavenReference(String currentProjPath, String groupId, String artifactId, String metadataPackageName, String packageVersion) {
        MavenPackageRefs mavenPackageRefs = new MavenPackageRefs();
        mavenPackageRefs.setGroupId(groupId);
        mavenPackageRefs.setArtifactId(artifactId);
        mavenPackageRefs.setVersion(packageVersion);
        mavenPackageRefs.setMetadataPackageName(metadataPackageName);
        MetadataProject metadataProject = metadataProjectCoreService.getMetadataProjInfo(currentProjPath);
        metadataProjectCoreService.updateMavenRefs(currentProjPath, metadataProject, mavenPackageRefs);
    }

    private void checkCircle(String currentProjPath, MetadataProject metadataProject, ProjectHeader projectHeader) {
        // 获取工程相对路径作为循环引用校验的key
        String projectRelativePath = ManagerUtils.getRelativePath(currentProjPath).toLowerCase();
        // 初始化引用链
        HashLinkedNodeMap chainOfRef = new HashLinkedNodeMap(projectRelativePath, projectRelativePath);
        List<ProjectHeader> projectHeaders = new ArrayList<>();
        List<ProjectHeader> projectRefs = metadataProject.getProjectRefs();
        if (projectRefs != null) {
            projectHeaders.addAll(projectRefs);
        }
        projectHeaders.add(projectHeader);

        getCircle(currentProjPath, projectHeaders, chainOfRef);
    }

    private void getCircle(String projectPath, List<ProjectHeader> projectRefs, HashLinkedNodeMap chainOfRef) {
        if (projectRefs != null && projectRefs.size() > 0) {
            projectRefs.forEach(projRef -> {
                Path projectRefPath = Paths.get(projectPath).resolve(projRef.getProjectPath());
                String projectRefRelativePath = ManagerUtils.getRelativePath(projectRefPath.normalize().toString()).toLowerCase();
                String checkDup = chainOfRef.putAfterCheckDup(projectRefRelativePath, projectRefRelativePath);
                if (!StringUtils.isEmpty(checkDup)) {
                    throw new LcmMetadataDevException(ErrorCodes.ECP_METADATA_DEV_0012, checkDup);
                }

                MetadataProject refMetadataProject = metadataProjectCoreService.getMetadataProjInfo(projectRefPath.toString());
                if(refMetadataProject == null) {
                    throw new LcmMetadataDevException(ErrorCodes.ECP_METADATA_DEV_0013, projectRefPath.normalize().toString());
                }
                getCircle(projectRefPath.toString(), refMetadataProject.getProjectRefs(), chainOfRef);
                chainOfRef.removeLast();
            });
        }
    }

    private void updateProjectReference(String currentProjPath, MetadataProject metadataProject, ProjectHeader projectHeader) {
        metadataProjectCoreService.updateProjectRefs(currentProjPath, metadataProject, projectHeader);
    }

    public GspMetadata getRefMetadata(String metadataID, String absolutePath) {
        if (absolutePath != null && !absolutePath.isEmpty()) {
            Utils.setMetadataPath(absolutePath);
        }
        return refCommonService.getRefMetadata(metadataID);
    }

    public GspMetadata getMetadataWithoutContent(String absolutePath) {
        return RepositoryFactory.getInstance().getMetadataRepository().getMetadataWithoutContent(absolutePath);
    }

    public void deleteMetadata(String absolutePath, String metadataFileName) {
        String fullPath = fileService.getCombinePath(absolutePath, metadataFileName);
        if (!isMetadataExist(fullPath)) {
            return;
        }
        // 如果不是元数据，则直接删除文件，如ts文件
        if (!isMetadata(fullPath)) {
            try {
                fileService.fileDelete(fullPath);
            } catch (IOException e) {
                log.error("删除文件[{}]失败", fullPath, e);
            }
            return;
        }

        GspMetadata metadataWithoutContent = getMetadataWithoutContent(fullPath);

        // 事件准备
        MetadataEventBroker broker = SpringBeanUtils.getBean(MetadataEventBroker.class);
        MetadataEventArgs args = new MetadataEventArgs();
        args.setMetadata(metadataWithoutContent);
        args.setPath(fullPath);

        // 删除前事件
        broker.fireMetadataDeletingEvent(args);
        // 删除元数据文件
        RepositoryFactory.getInstance().getMetadataRepository().delete(fullPath);
        // 删除后事件
        broker.fireMetadataDeletedEvent(args);
    }

    public void deleteFolder(String absolutePath) {
        DirEventBroker broker = SpringBeanUtils.getBean(DirEventBroker.class);
        DirEventArgs args = new DirEventArgs();
        args.setPath(absolutePath);

        broker.fireDirDeletingEvent(args);

        try {
            fileService.deleteAllFilesUnderDirectory(absolutePath);
        } catch (IOException e) {
            throw new LcmFileDevException(e, ErrorCodes.ECP_FILE_DEV_0011, absolutePath);
        }

        broker.fireDirDeletedEvent(args);
    }

    public void renameMetadata(String oldFileName, String newFileName, String absolutePath) {
        if (oldFileName.equals(newFileName)) {
            return;
        }
        String oldFilePath = fileService.getCombinePath(absolutePath, oldFileName);
        if (!isMetadataExist(oldFilePath)) {
            throw new LcmFileDevException(ErrorCodes.ECP_FILE_DEV_0001, oldFilePath);
        }
        String newFilePath = fileService.getCombinePath(absolutePath, newFileName);
        if (!isMetadataExist(newFilePath)) {
            throw new LcmFileDevException(ErrorCodes.ECP_FILE_DEV_0003, newFilePath);
        }

        validateMetadataCode(newFileName.substring(0, newFileName.lastIndexOf("\\.")), false);
        RepositoryFactory.getInstance().getMetadataRepository().rename(oldFilePath, newFilePath);

        // 修改文件内容，将 元数据头结点元数据名称一起修改
        GspMetadata metadata = loadMetadata(newFileName, absolutePath);
        metadata.getHeader().setName(newFileName.substring(0, newFileName.lastIndexOf("\\.")));
        RepositoryFactory.getInstance().getMetadataRepository().save(metadata, newFilePath);
    }

    private void validateMetadataCode(String code, boolean isLanguageMetadata) {
        if (code.length() > 255) {
            throw new LcmMetadataDevException(ErrorCodes.ECP_METADATA_DEV_0014, code);
        }
        String rexStr = isLanguageMetadata ? "^[a-zA-Z_-\\x7f-\\xff][a-zA-Z0-9-._\\x7f-\\xff]*$" : "^[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9._\\x7f-\\xff]*$";
        if (!Pattern.matches(rexStr, code)) {
            throw new LcmMetadataDevException(ErrorCodes.ECP_METADATA_DEV_0015, code);
        }
    }

    public List<MetadataDto> getMetadataListInBo(String projPath, List<String> metadataTypes) {
        List<String> projectsInBo = metadataProjectCoreService.getProjectsInBoByProjPath(projPath);

        // 生成型只能引用生成型，解析型可以引用生成型和解析型
        final MetadataProject metadataProjInfo = metadataProjectCoreService.getMetadataProjInfo(projPath);
        boolean isGenerationFlag = metadataProjInfo.getMetadataPackageInfo().getProcessMode() == null || metadataProjInfo.getMetadataPackageInfo().getProcessMode().equals(ProcessMode.generation);

        if (isGenerationFlag && !MetadataRefConfigHelper.getInstance().isAllowInterpretationRefer()) {
            projectsInBo = projectsInBo.stream().filter(project -> {
                MetadataProject metadataProjInfoInBo = metadataProjectCoreService.getMetadataProjInfo(project);
                return metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode() == null || metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode().equals(ProcessMode.generation);
            }).collect(Collectors.toList());
        }

        // 获取列表，生成型只能引用生成型，解析型可以引用生成型和解析型
        List<MetadataDto> metadataList = new ArrayList<>();
        projectsInBo.forEach(project -> {
            MetadataProject metadataProjInfoInBo = metadataProjectCoreService.getMetadataProjInfo(project);

            if (isGenerationFlag && !MetadataRefConfigHelper.getInstance().isAllowInterpretationRefer()) {
                boolean isEachProjectGenerationFlag = metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode() == null || metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode().equals(ProcessMode.generation);
                if (!isEachProjectGenerationFlag) {
                    return;
                }
            }

            String metadataProjPath = project + File.separator + Utils.getMetadataProjPath();
            List<GspMetadata> result = getMetadataList(metadataProjPath, metadataTypes);
            for (GspMetadata metadata : result) {
                MetadataDto metadataDto = MetadataDtoConverter.asDto(metadata);
                metadataDto.setProjectName(new File(project).getName());
                metadataDto.setProcessMode(metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode() == null ? ProcessMode.generation.toString() : metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode().toString());
                metadataList.add(metadataDto);
            }
        });
        return metadataList;
    }

    /**
     * 获取本地元数据
     * @param text
     * @param projPath
     * @param metadataTypes
     * @return
     */
    public List<Metadata4Ref> getMetadata4RefListInBo(String text, String projPath, List<String> metadataTypes) {
        List<String> projectsInBo = metadataProjectCoreService.getProjectsInBoByProjPath(projPath);

        // 获取列表，生成型只能引用生成型，解析型可以引用生成型和解析型
        boolean isGenerationFlag = isGenerationProject(projPath);
        List<Metadata4Ref> metadataList = new ArrayList<>();
        projectsInBo.forEach(project -> {
            MetadataProject metadataProjInfoInBo = metadataProjectCoreService.getMetadataProjInfo(project);
            if (isGenerationFlag && !MetadataRefConfigHelper.getInstance().isAllowInterpretationRefer()) {
                boolean isEachProjectGenerationFlag = metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode() == null || metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode().equals(ProcessMode.generation);
                if (!isEachProjectGenerationFlag) {
                    return;
                }
            }
            MetadataPackageHeader metadataPackageHeader = metadataProjInfoInBo.getMetadataPackageInfo();
            if (metadataPackageHeader.getProcessMode() == null) {
                metadataPackageHeader.setProcessMode(ProcessMode.generation);
            }

            String metadataProjPath = project + File.separator + Utils.getMetadataProjPath();
            List<GspMetadata> result = getMetadataList(metadataProjPath, metadataTypes);
            for (GspMetadata metadata : result) {
                Metadata4Ref metadata4Ref = new Metadata4Ref(metadataPackageHeader, new ServiceUnitInfo(), metadata);
                if (isValidMd(metadata4Ref, text)) {
                    metadataList.add(metadata4Ref);
                }
            }
        });
        return metadataList;
    }

    /**
     * 根据路径判断工程是否是生成型
     * @param projPath 元数据工程路径
     * @return 工程是否为生成型
     */
    public boolean isGenerationProject(String projPath) {
        final MetadataProject metadataProjInfo = metadataProjectCoreService.getMetadataProjInfo(projPath);
        return metadataProjInfo.getMetadataPackageInfo().getProcessMode() == null || metadataProjInfo.getMetadataPackageInfo().getProcessMode().equals(ProcessMode.generation);
    }

    /**
     * 根据BO路径获取BO内所有符合条件的元数据列表
     *
     * @param boPath        业务对象绝对路径
     * @param metadataTypes 元数据类型过滤条件
     * @param searchText    元数据名称过滤条件
     * @return 元数据列表
     * @author sunhongfei01
     * @since 2022-4-19
     */
    public List<MetadataDto> getMetadataListInBoByBoPath(String boPath, List<String> metadataTypes, String searchText) {
        // 构造返回元数据列表
        List<MetadataDto> metadataList = new ArrayList<>();

        // 获取所有的元数据类型, 并获得postfix和 typecode映射关系
        Map<String, String> mdTypeMap = getMetadataTypeList().stream()
                .collect(Collectors.toMap(MetadataType::getPostfix, MetadataType::getTypeCode));

        if (!mdTypeMap.containsKey(".dbo")) {
            mdTypeMap.put(".dbo", "DBO");
        }

        // 若未声明查询元数据类型,则获取所有元数据类型postfix
        boolean isAllMetadataType = CollectionUtils.isEmpty(metadataTypes);
        // 获取所有待查询的元数据类型set
        Set<String> metadataTypeSet;
        if (isAllMetadataType) {
            metadataTypeSet = mdTypeMap.keySet();
        } else {
            metadataTypeSet = new HashSet<>(metadataTypes);
        }

        // 查询bo下所有工程列表
        List<String> projectsInBo = metadataProjectCoreService.getProjectsInBo(boPath);

        // 遍历工程,获取所有的元数据路径
        List<String> metadataPaths = new ArrayList<>();
        Map<String, String> projPathAndMdPathMap = new HashMap<>();
        Map<String, Properties> mdSavePropertiesMap = new HashMap<>();
        for (String projectPath : projectsInBo) {
            // 获取该工程下所有的元数据文件路径
            List<String> metadataPathsInBo = new ArrayList<>();
            String metadataProjPath = projectPath + File.separator + Utils.getMetadataProjPath();
            RepositoryFactory.getInstance().getMetadataRepository().getMetadatasUnderDir(metadataPathsInBo, metadataProjPath);
            // 构建键为元数据路径，值为工程路径的map
            projPathAndMdPathMap.putAll(metadataPathsInBo.stream()
                    .collect(Collectors.toMap(metadataPath -> metadataPath, metadataProjectPath -> projectPath))
            );
            // 汇总所有元数据路径
            metadataPaths.addAll(metadataPathsInBo);
            // 遍历工程目录缓存METADATA_SAVE文件，使用map避免重复问题
            mdSavePropertiesMap.put(projectPath, PropertiesUtil.getProperties(FileServiceImp.combinePath(projectPath, METADATA_BIN_PATH, OperationEnum.METADATA_SAVE.toString())));
        }

        // 拼接bo内元数据名称缓存文件路径
        File ideFile = new File(Paths.get(boPath, IDE_FOLDERNAME).normalize().toString());
        if(!ideFile.exists()){
            ideFile.mkdir();
        }
        String cachePath = Paths.get(ideFile.getPath(), METADATAINBO_INDEX_FILENAME).normalize().toString();
        // 读取缓存文件 并获取缓存文件中所有的键
        Properties properties = PropertiesUtil.getProperties(cachePath);
        Set<Object> deletedPropKeySet = new HashSet<>(properties.keySet());
        // 标识当前缓存文件记录信息是否比bo内实际元数据多
        boolean isPropertisNeedChange = false;

        // 当前语言
        String currentLanguage = RuntimeContext.getLanguage();
        for (String metadataPath : metadataPaths) {
            // 根据元数据文件后缀判断元数据类型是否在过滤条件中,若未传递过滤条件则不做过滤
            File metadataFile = new File(metadataPath);
            String extension = fileService.getExtension(metadataFile);
            if (!metadataTypeSet.contains(extension)) {
                continue;
            }

            // 根据元数据文件路径获取其相对工作空间 的相对路径
            String mdRelativePath;
            try {
                mdRelativePath = ManagerUtils.getRelativePath(metadataFile.getCanonicalPath());
            } catch (IOException e) {
                throw new LcmMetadataDevException(e, ErrorCodes.ECP_METADATA_DEV_0016, metadataPath);
            }

            // 拼接元数据对应缓存文件中的key: 1.记录元数据文件更新时间的lastChangeOn  2.记录元数据名称的metadataName
            String cacheLastChangeOnKey = mdRelativePath + Utils.LAST_CHANGE_ON;
            String cacheMetadataNameKey = mdRelativePath + ".metadataName_"+currentLanguage;
            String cacheMetadataIdKey = mdRelativePath + ".metadataId";
            String cacheMetadataCodeKey = mdRelativePath + ".metadataCode";
            // 缓存文件key集合中移除
            deletedPropKeySet.remove(cacheLastChangeOnKey);
            deletedPropKeySet.remove(cacheMetadataNameKey);
            deletedPropKeySet.remove(cacheMetadataIdKey);
            deletedPropKeySet.remove(cacheMetadataCodeKey);

            // 获取缓存中的 元数据更新时间 和元数据文件的更新时间
            String lastChangeOn = properties.getProperty(cacheLastChangeOnKey);
            String fileLastModify = String.valueOf(metadataFile.lastModified());

            // 构造元数据MetadataDto 的文件名\元数据类型等其他属性(可通过文件名直接获取到)
            MetadataDto metadataDto = new MetadataDto();
            metadataDto.setType(mdTypeMap.get(extension));
            metadataDto.setRelativePath(mdRelativePath);
            metadataDto.setFileName(metadataFile.getName());

            // 获取缓存中元数据名称
            String metadataNameProperty = properties.getProperty(cacheMetadataNameKey);
            String metadataIdProperty = properties.getProperty(cacheMetadataIdKey);
            String metadataCodeProperty = properties.getProperty(cacheMetadataCodeKey);
            // 若文件更新时间未发生改变且 缓存中存在元数据名称(防止数据缺失),则使用缓存中的元数据名称
            if (fileLastModify.equals(lastChangeOn)
                    && StringUtils.hasLength(metadataNameProperty)
                    && StringUtils.hasLength(metadataIdProperty)
                    && StringUtils.hasLength(metadataCodeProperty)) {
                metadataDto.setName(metadataNameProperty);
                metadataDto.setId(metadataIdProperty);
                metadataDto.setCode(metadataCodeProperty);
            } else {
                if (".dbo".equals(extension)) {
                    AbstractDatabaseObject databaseObject = databaseObjectService.getDatabaseObject(metadataPath);
                    metadataDto.setCode(databaseObject.getCode());
                    metadataDto.setId(databaseObject.getId());
                    metadataDto.setName(databaseObject.getName());
                } else {
                    // 若缓存中不存在, 则反序列化文件获取元数据内容
                    GspMetadata metadataWithoutContent = getMetadataWithoutContent(metadataPath);
                    metadataDto.setName(metadataWithoutContent.getHeader().getName());
                    metadataDto.setId(metadataWithoutContent.getHeader().getId());
                    metadataDto.setCode(metadataWithoutContent.getHeader().getCode());
                }
                // 标识缓存文件需要更新
                isPropertisNeedChange = true;

                // 将元数据文件信息写入properties中
                properties.setProperty(cacheLastChangeOnKey, fileLastModify);
                properties.setProperty(cacheMetadataNameKey, metadataDto.getName());
                properties.setProperty(cacheMetadataIdKey, metadataDto.getId());
                properties.setProperty(cacheMetadataCodeKey, metadataDto.getCode());
            }

            // 若存在元数据名称过滤条件, 则判断是否符合
            if (!StringUtils.hasLength(searchText) || metadataDto.getName().contains(searchText)) {
                metadataList.add(metadataDto);
            }

            // 设置最新修改人和最新修改时间
            getMetadataLastChange(metadataDto, mdSavePropertiesMap, projPathAndMdPathMap.get(metadataPath));
        }

        // 若过滤条件未过滤元数据类型(若进行过滤,此时properties比元数据过滤结果多认为是正常的), 且properties比实际元数据数量多
        if (isAllMetadataType && !CollectionUtils.isEmpty(deletedPropKeySet)) {
            // 标识properties需要更新
            isPropertisNeedChange = true;
            // 遍历properties比实际元数据文件多的项, 将其删除
            for (Object key : deletedPropKeySet) {
                properties.remove(key);
            }
        }

        // 若properties发生了变动, 调用工具类更新缓存文件
        if (isPropertisNeedChange) {
            PropertiesUtil.setProperties(cachePath, properties);
        }
        return metadataList;
    }

    /**
     * 获取元数据最新修改人、修改时间
     * @param metadata 元数据
     * @param mdSavePropertiesMap METADATA_SAVE缓存map
     * @param projPath 工程绝对路径
     */
    public void getMetadataLastChange(MetadataDto metadata, Map<String, Properties> mdSavePropertiesMap, String projPath){
        String mdRelativePath = metadata.getRelativePath();
        String relativeProjPath =  ManagerUtils.getRelativePath(projPath);
        // 根据projPath获取唯一的properties
        Properties mdSaveProperties = mdSavePropertiesMap.get(projPath);

        String key = FileServiceImp.getRelativePath(mdRelativePath, relativeProjPath);
        // 设置修改时间
        String lastChangeOn = mdSaveProperties.getProperty(key + Utils.LAST_CHANGE_ON);
        if(StringUtils.hasLength(lastChangeOn)){
            metadata.setLastChangedOn(lastChangeOn);
        }
        // 设置修改人
        String lastChangeBy = mdSaveProperties.getProperty(key + Utils.LAST_CHANGE_BY);
        if(StringUtils.hasLength(lastChangeBy)){
            // 根据userId获取用户名
            User userBasicInfo = getUserManager().getUserBasicInfo(lastChangeBy);
            if (userBasicInfo != null) {
                lastChangeBy = userBasicInfo.getName();
                metadata.setLastChangedBy(lastChangeBy);
            }
        }
    }

    public List<GspMetadata> getMetadataList(String absolutePath, List<String> metadataTypes) {
        String projPath = metadataProjectCoreService.getProjPath(absolutePath);
        projPath = FileServiceImp.handlePath(projPath);
        // 编译时缓存可用
        return MetadataInProjectManager.getMetadataListInProject(projPath, metadataTypes);

    }

    /**
     *  根据元数据ID在工程中获取到完整元数据
     * @param absolutePath
     * @param metadataID
     * @return
     */
    public GspMetadata getMetadataWithContentInProjectByID(String absolutePath, String metadataID) {
        String projPath = metadataProjectCoreService.getProjPath(absolutePath);
        projPath = FileServiceImp.handlePath(projPath);
        return MetadataInProjectManager.getMetadataWithContentInProjectByID(projPath,metadataID);

    }

    public List<String> getMetadataPaths(String absolutePath, List<String> metadataTypes) {
        List<String> metadataPaths = new ArrayList<>();
        //获取目录下的所有文件路径
        RepositoryFactory.getInstance().getMetadataRepository().getMetadatasUnderDir(metadataPaths, absolutePath);
        metadataTypes = CollectionUtils.isEmpty(metadataTypes) ? Utils.getMetadataPostfixTypes() : metadataTypes;
        List<String> filteredMetadataPaths = new ArrayList<>();
        for (String path : metadataPaths) {
            String extension = fileService.getExtension(path);
            if (metadataTypes.contains(extension)) {
                filteredMetadataPaths.add(path);
            }
        }
        return filteredMetadataPaths;
    }

    public List<MetadataType> getMetadataTypeList() {
        return MetadataTypeHelper.getInstance().getMetadataTypes();
    }

    public boolean isMetadataExist(String absolutePath) {
        return fileService.isFileExist(absolutePath);
    }

    public boolean isMetadataExistInProject(String projPath, String metadataID) {
        MetadataProject metadataProjInfo = metadataProjectCoreService.getMetadataProjInfo(projPath);
        Utils.checkNPE(metadataProjInfo, "获取的元数据工程信息为空，参数为projPath：" + projPath);
        List<GspMetadata> metadataList = getMetadataList(metadataProjInfo.getProjectPath());
        return metadataList.stream().anyMatch(metadata -> metadata.getHeader().getId().equals(metadataID));
    }

    /**
     * 根据元数据ID在bo内所有工程中查找
     * @param projPath
     * @param metadataID
     * @return
     */
    public GspMetadata loadMetadataInProjectByMetadataID(String projPath, String metadataID) {
        MetadataProject metadataProjInfo = metadataProjectCoreService.getMetadataProjInfo(projPath);
        Utils.checkNPE(metadataProjInfo, "获取的元数据工程信息为空，参数为projPath：" + projPath);
        List<GspMetadata> metadataList = getMetadataList(metadataProjInfo.getProjectPath());
        return metadataList.stream().filter(metadata -> metadata.getHeader().getId().equals(metadataID)).findFirst().orElse(null);
    }

    public String getRefPath(String absolutePath) {
        MetadataProject metadataProjInfo = metadataProjectCoreService.getMetadataProjInfo(absolutePath);
        return fileService.getCombinePath(metadataProjInfo.getProjectPath(), Utils.getMetadataBinPath());
    }

    public MetadataHeader getRefMetadataHeader(String metadataID, String absolutePath) {
        GspMetadata metadata = getRefMetadata(metadataID, absolutePath);
        Utils.checkNPE(metadata, "在工程" + absolutePath + "及其依赖中，无法找到元数据" + metadataID);
        return metadata.getHeader();
    }

    public List<MetadataHeader> getResourceMetadata(String metadataId, String proPath) {
        final List<GspMetadata> metadataList = getMetadataList(proPath);
        GspMetadata metadata = new GspMetadata();
        if (metadataList != null) {
            for (GspMetadata item : metadataList) {
                if (item.getHeader().getId().equals(metadataId)) {
                    metadata = item;
                    break;
                }
            }
        }
        List<MetadataHeader> metadataHeader = new ArrayList<>();
        if (metadata.getRefs() != null) {
            metadata.getRefs().forEach(item -> {
                if ("ResourceMetadata".equals(item.getDependentMetadata().getType())) {
                    metadataHeader.add(item.getDependentMetadata());
                }
            });
        }
        return metadataHeader;
    }

    public void setMetadataUri(String absolutePath) {
        Utils.setMetadataPath(absolutePath);
    }

    public GspMetadata getI18nMetadata(String fileName, String absolutePath, String language) {
        I18nCoreService i18nCoreService = new I18nCoreService();
        return i18nCoreService.getI18nMetadata(fileName, absolutePath, language);
    }

    public List<GspMetadata> getRefI18nMetadata(String resourceMdID, String resourceFileName, String path) {
        RefI18nMetadataFactory refI18nMetadataFactory = new RefI18nMetadataFactory();
        IRefI18nFilter filter = refI18nMetadataFactory.createFilter(resourceMdID, path);
        return filter.getRefI18nMetadata(resourceMdID, resourceFileName, path);
    }

    public List<GspMetadata> getMetadataList(String absolutePath) {
        //先从缓存获取
        String projPath = metadataProjectCoreService.getProjPath(absolutePath);
        if (!StringUtils.hasLength(projPath)) {
            return null;
        }
        return MetadataInProjectManager.getMetadataListInProject(projPath);
    }

    public MetadataPackage getMetadataPackageInfo(String packageFileName, String packagePath) {
        String packageFullName = Utils.handlePackageName(packageFileName);

        String absolutePath = fileService.getCombinePath(packagePath, packageFullName);
        if (fileService.isFileExist(absolutePath)) {
            MetadataPackage metadataPackage = getMetadataPackage(packagePath, absolutePath);
            metadataPackage.getHeader().setLocation(Utils.handlePath(packagePath));
            return metadataPackage;
        } else {
            List<File> dirs = fileService.getDirectorys(packagePath);
            for (File dir : dirs) {
                String targetFile = fileService.getCombinePath(dir.getPath(), packageFullName);
                if (fileService.isFileExist(targetFile)) {
                    MetadataPackage metadataPackage = getMetadataPackage(packagePath, targetFile);
                    metadataPackage.getHeader().setLocation(Utils.handlePath(dir.getPath()));
                    return metadataPackage;
                }
            }
        }

        return null;
    }

    public List<GspMetadata> getMetadataListByRefedMetadataId(String path, String metadataId) {
        List<GspMetadata> metadataList = new ArrayList<>();
        List<String> projPaths = metadataProjectCoreService.getProjPathsInBoByRefedProjPath(path);
        projPaths.add(path);
        projPaths.forEach(projPath -> {
            List<GspMetadata> metadataListInProject = getMetadataList(projPath);
            metadataList.addAll(metadataListInProject.stream().filter(metadata -> {
                if (metadata.getRefs() == null) {
                    return false;
                }
                return metadata.getRefs().stream().anyMatch(ref -> ref.getDependentMetadata().getId().equals(metadataId));
            }).collect(Collectors.toList()));
        });
        return metadataList;
    }

    public boolean isMetadataRefed(String path) {
        if (!isMetadata(path)) {
            return false;
        }
        String mdName = new File(path).getName();
        final GspMetadata metadataWithoutContent = getMetadataWithoutContent(path);
        final String projPath = metadataProjectCoreService.getProjPath(path);
        final Map<String, List<GspMetadata>> metadataHashMapByRefedMetadataId = getMetadataHashMapByRefedMetadataId(projPath, metadataWithoutContent.getHeader().getId());
        boolean isMetadataRefedFlag = metadataHashMapByRefedMetadataId.size() > 0;
        if (isMetadataRefedFlag) {
            metadataHashMapByRefedMetadataId.forEach((projName, metadataList) -> {
                metadataList.forEach(metadata -> {
                    String log = LcmMetadataDevLog.getInstance().getString(LogCodes.LOG_METADATA_DEV_0013, projName, metadata.getHeader().getFileName(), mdName);
                    if (Objects.nonNull(IdeLogUtils.getIdeLogService())) {
                        IdeLogUtils.getIdeLogService().pushLog(log, CAFContext.current.getUserId());
                    }
                });
            });
        }
        return isMetadataRefedFlag;
    }

    private boolean isMetadata(String path) {
        List<MetadataType> metadataTypeList = getMetadataTypeList();
        return metadataTypeList.stream().anyMatch(metadataType -> path.endsWith(metadataType.getPostfix()));
    }

    private Map<String, List<GspMetadata>> getMetadataHashMapByRefedMetadataId(String path, String metadataId) {
        Map<String, List<GspMetadata>> metadataHashMap = new HashMap<>();
        List<String> projPaths = metadataProjectCoreService.getProjPathsInBoByRefedProjPath(path);
        projPaths.add(path);
        projPaths.forEach(projPath -> {
            List<GspMetadata> metadataListInProject = getMetadataList(projPath);
            List<GspMetadata> metadataList = metadataListInProject.stream().filter(metadata -> {
                if (metadata.getRefs() == null || metadataId.equals(metadata.getHeader().getId())) {
                    return false;
                }
                return metadata.getRefs().stream().anyMatch(ref -> ref.getDependentMetadata().getId().equals(metadataId));
            }).collect(Collectors.toList());
            if (metadataList.size() > 0) {
                metadataHashMap.put(new File(projPath).getName(), metadataList);
            }
        });
        return metadataHashMap;
    }

    public Metadata4Ref getMetadataFromPackage(String packageName, String packagePath, String metadataId) {
        String packageFullName = Utils.handlePackageName(packageName);

        MetadataPackage packageInfo = getMetadataPackageInfo(packageFullName, packagePath);
        if (packageInfo == null) {
            return null;
        }
        GspMetadata metadata = null;
        String absolutePath = fileService.getCombinePath(packageInfo.getHeader().getLocation(), packageFullName);
        for (GspMetadata item : packageInfo.getMetadataList()) {
            if (item.getHeader().getId().equals(metadataId)) {
                lock.lock();
                File file = new File(absolutePath);
                try(ZipFile zf = new ZipFile(file);
                    InputStream in = new BufferedInputStream(new FileInputStream(absolutePath));
                    ZipInputStream zin = new ZipInputStream(in, StandardCharsets.UTF_8)) {
                    ZipEntry ze;
                    StringBuilder sb = new StringBuilder();
                    while ((ze = zin.getNextEntry()) != null) {
                        try (BufferedReader br = new BufferedReader(
                                new InputStreamReader(zf.getInputStream(ze), StandardCharsets.UTF_8))) {
                            if (fileService.getFileName(ze.toString()).equals(fileService.getFileName(item.getRelativePath()))) {
                                String line;
                                while ((line = br.readLine()) != null) {
                                    sb.append(line);
                                }
                                break;
                            }
                        } catch (IOException e) {
//                                e.printStackTrace();
                            throw new IOException("读取元数据失败", e);
                        }
                    }
                    metadata = new MetadataSerializer().deserialize(sb.toString(), GspMetadata.class);

                } catch (IOException | RuntimeException e) {
                    log.error("反序列化元数据失败,路径为：" + packagePath + "包名为：" + packageName, e);
                    throw new LcmMetadataDevException(e, ErrorCodes.ECP_METADATA_DEV_0017, packagePath, packageName);
                } finally {
                    lock.unlock();
                }
            }
        }
        Metadata4Ref metadataDt = new Metadata4Ref();
        metadataDt.setPackageHeader(packageInfo.getHeader());
        metadataDt.setMetadata(metadata);

        return metadataDt;
    }

    public List<GspMetadata> getlresMetadataFromPackage(String resourceMdID, String resourceMdFileName, String metadataPackageLocation) {
        File packageFile = new File(metadataPackageLocation);
        //必须用GetMetadataPackageInfoFromSpecPath获取包的信息
        MetadataPackage metadataPackageInfo = getMetadataPackageInfo(packageFile.getName(), packageFile.getParent());
        //根据包具体的信息，对比metadataid，找到metadataid对应元数据的相对路径，其中找语言包元数据列表
        if (metadataPackageInfo == null || metadataPackageInfo.getMetadataList() == null) {
            throw new LcmMetadataDevException(ErrorCodes.ECP_METADATA_DEV_0018, resourceMdFileName);
        }

        FileService fileService = SpringBeanUtils.getBean(FileService.class);
        List<GspMetadata> lresMetadataList = new ArrayList<>();
        for (GspMetadata gspMetadata : metadataPackageInfo.getMetadataList()) {
            if (resourceMdID.equals(gspMetadata.getHeader().getId())) {
                String resourceMdFileNameWithoutExt = fileService.getFileNameWithoutExtension(gspMetadata.getHeader().getFileName());
                for (GspMetadata metadata : metadataPackageInfo.getMetadataList()) {
                    if (metadata.getHeader().getFileName().endsWith(Utils.getLanguageMetadataFileExtention()) && metadata.getHeader().getFileName().startsWith(resourceMdFileNameWithoutExt)) {
                        Metadata4Ref metadataFromPackage = getMetadataFromPackage(packageFile.getName(), packageFile.getParent(), metadata.getHeader().getId());
                        lresMetadataList.add(metadataFromPackage.getMetadata());
                    }
                }
                break;
            }
        }

        return lresMetadataList;
    }

    public MetadataProject getMetadataProjInfo(String absolutePath) {
        String assemblyName = "";
        MetadataProject project;
        String projPath = MetadataProjectCoreService.getCurrent().getProjPath(absolutePath);
        String metadataPath = fileService.getCombinePath(projPath, Utils.getMetadataProjPath());
        if (fileService.isDirectoryExist(metadataPath)) {
            GspProject gspProject = new GspProjectCoreService().getGspProjectInfo(absolutePath);
            assemblyName = gspProject.getMetadataPackageName();
        }
        project = metadataProjectCoreService.getMetadataProjInfo(projPath);
        project.setCsprojAssemblyName(assemblyName);
        return project;
    }

    public List<MetadataIndexItemDto> getRemoteMetadataIndexList(String text, String path, String selectedPackageSource, List<String> typeList, boolean page, int pageSize, int pageIndex, boolean isFilterByRefs, boolean conflictAvoidFlag) {
        Utils.checkEmpty(path, "获取的路径为空：" + path);
        MetadataProject metadataProjInfo = getMetadataProjInfo(path);

        if (metadataProjInfo != null) {
            if (isFilterByRefs && (metadataProjInfo.getMavenPackageRefs() == null || metadataProjInfo.getMavenPackageRefs().size() == 0)) {
                return new ArrayList<>();
            }
        }

        try {
            String pageWebapiOfIndexServer = IndexServerManager.getInstance().getPageWebapiOfIndexServerWithProcessMode();
            ProcessMode processMode = metadataProjInfo.getMetadataPackageInfo().getProcessMode() == null ? ProcessMode.generation : metadataProjInfo.getMetadataPackageInfo().getProcessMode();
            MetadataInfoFilterWithProcessMode filter = getMetadataInfoFilter(text, typeList, page, pageSize, pageIndex, selectedPackageSource, path, isFilterByRefs, processMode);
            PageMetadataInfoWithProcessMode pageMetadataInfoWithProcessMode = RestTemplateService.instance.getObjectByPost(pageWebapiOfIndexServer, filter);
            List<MetadataInfoWithVersionWithProcessMode> metadataInfos = pageMetadataInfoWithProcessMode.getMetadataInfos();
            return buildIndexDtoFromMetadataInfoWithVersionWithProcessMode(metadataInfos);
        } catch (Exception e) {
            log.error("读取索引服务错误：" + e);
            String pageWebapiOfIndexServer = IndexServerManager.getInstance().getPageWebapiOfIndexServer();
            MetadataInfoFilter filter = getMetadataInfoFilter(text, typeList, page, pageSize, pageIndex, selectedPackageSource, path, isFilterByRefs);
            PageMetadataInfo pageMetadataInfo = RestTemplateService.instance.getObjectByPost(pageWebapiOfIndexServer, filter);
            List<MetadataInfoWithVersion> metadataInfos = pageMetadataInfo.getMetadataInfos();
            return buildIndexDtoFromMetadataInfoWithVersion(metadataInfos);
        }
    }

    public void throwMetadataNotFoundException(String metadataId) {
        final MetadataInfoWithVersion metadataInfoWithVersion = getIndexByMetadataId(metadataId);
        StringBuilder sb = new StringBuilder();
        sb.append("未找到元数据：");
        sb.append(metadataId);
        if (metadataInfoWithVersion != null) {
            sb.append("，元数据Code为：");
            sb.append(metadataInfoWithVersion.getMetadataCode());
            sb.append("，元数据包名为：");
            sb.append(metadataInfoWithVersion.getPackageCode()).append(Utils.getMetadataPackageExtension());
        }
        String msg = sb.toString();
        throw new MetadataNotFoundException("Lcm", MetadataExceptionCode.METADATA_NOT_FOUND, msg, null);
    }

    private MetadataInfoWithVersion getIndexByMetadataId(String metadataId) {/*
        String metadataWebapiOfIndexServer = IndexServerManager.getInstance().getMetadataWebapiOfIndexServer() + "?metadataId=" + metadataId;
        List<MetadataInfoWithVersion> metadataInfoWithVersionList = RestTemplateService.instance.getObjectByGet(metadataWebapiOfIndexServer);
        if (metadataInfoWithVersionList != null && metadataInfoWithVersionList.size() > 0) {
            return metadataInfoWithVersionList.get(0);
        }*/
        return null;
    }

    public List<MetadataIndexItemDto> getLocalMetadataList(String text, String absolutePath, List<String> typeList, boolean page, int pageSize, int pageIndex, String packagePath) {
        List<MetadataIndexItemDto> mds = new ArrayList<>();
        // 根据索引，返回元数据dto列表
        List<LocalMetadataIndexItem> localMdIndexList = MetadataIndexCacheService.getInstance().getLocalPackagesMdIndexDic(packagePath);

        if (localMdIndexList == null || localMdIndexList.size() < 1) {
            return mds;
        }

        // 解析型
        final MetadataProject metadataProjInfo = getMetadataProjInfo(absolutePath);
        boolean isGenerationFlag = metadataProjInfo.getMetadataPackageInfo().getProcessMode() == null || metadataProjInfo.getMetadataPackageInfo().getProcessMode().equals(ProcessMode.generation);

        if (isGenerationFlag && !MetadataRefConfigHelper.getInstance().isAllowInterpretationRefer()) {
            localMdIndexList = localMdIndexList.stream().filter(localMetadataIndexItem -> localMetadataIndexItem.getProcessMode() == null || localMetadataIndexItem.getProcessMode().equals(ProcessMode.generation.toString())).collect(Collectors.toList());
        }

        String packageNameExcluded = "";
        if (!(absolutePath == null || absolutePath.isEmpty())) {
            MetadataProject projInfo = metadataProjectCoreService.getMetadataProjInfo(absolutePath);
            if (projInfo != null) {
                packageNameExcluded = projInfo.getMetadataPackageInfo().getName();
            }
            if (!page) {
                for (LocalMetadataIndexItem localMdIndex : localMdIndexList) {
                    if (isPackMd(localMdIndex, typeList, text, packageNameExcluded)) {
                        MetadataIndexItemDto dto = assemblyMetadataIndexItemDto(localMdIndex);
                        mds.add(dto);
                    }
                }
            } else {
                int count = 0;
                int skip = pageIndex * pageSize;
                int max = pageSize + skip;
                for (LocalMetadataIndexItem localMdIndex : localMdIndexList) {
                    if (count >= max) {
                        break;
                    }
                    if (isPackMd(localMdIndex, typeList, text, packageNameExcluded)) {
                        count++;
                        if (count <= skip) {
                            continue;
                        }
                        MetadataIndexItemDto dto = assemblyMetadataIndexItemDto(localMdIndex);
                        mds.add(dto);
                    }
                }

            }
        }
        return mds;
    }

    public List<MetadataIndexItemDto> getDBMetadataList(String text, String absolutePath, List<String> typeList, boolean page, int pageSize, int pageIndex) {
        List<String> typeListForDB = getTypeListForDB(typeList);
        MetadataProject metadataProject = getMetadataProjInfo(absolutePath);
        return getDBMetadataList(text, absolutePath, typeListForDB, page, pageSize, pageIndex, metadataProject);
    }

    private List<String> getTypeListForDB(List<String> typeList) {
        // 检查类型是否正确
        List<String> typeListForDB = new ArrayList<>();
        if (!CollectionUtils.isEmpty(typeList)) {
            List<MetadataType> typeListDict = getMetadataTypeList();
            typeListDict.forEach(type -> {
                if (typeList.contains(type.getPostfix().toLowerCase())) {
                    typeListForDB.add(type.getTypeCode());
                }
            });
        }
        return typeListForDB;
    }

    /**
     * 根据元数据文件后缀查询指定类型元数据列表
     * @param postfixList 元数据文件后缀
     * @param metadataProject 元数据工程
     * @return 工程下符合类型条件的元数据列表
     */
    public List<Metadata4Ref> getMetadata4RefListByPostfixList(List<String> postfixList, MetadataProject metadataProject) {
        List<String> typeList = getTypeListForDB(postfixList);
        return getMetadata4RefListByTypeList(typeList, metadataProject);
    }

    /**
     * 根据条件分页查询元数据列表
     * @param text
     * @param absolutePath
     * @param typeList
     * @param pageSize
     * @param pageIndex
     * @return
     */
    public MetadataIndexDto getUnionMetadataListByPage(String text, String absolutePath, List<String> typeList, int pageSize, int pageIndex) {
        // 本地bo中元数据
        List<Metadata4Ref> metadata4RefInBo = getMetadata4RefListInBo(text, metadataProjectCoreService.getProjPath(absolutePath), typeList);
        // 对本地元数据进行分页
        List<Metadata4Ref> metadata4RefsInBoForPage = metadata4RefInBo.stream().skip((pageIndex - 1) * pageSize).limit(pageSize).collect(Collectors.toList());

        MetadataProject metadataProject = getMetadataProjInfo(absolutePath);

        GspProject gspProjectInfo = gspProjectCoreService.getGspProjectInfo(absolutePath);
        // 数据库中元数据
        Metadata4RefPageQueryResult queryResult = getMetadata4RefListInDB(text, gspProjectInfo.getBizobjectID(),metadata4RefInBo.size(), metadata4RefsInBoForPage.size(), typeList, metadataProject, pageSize, pageIndex);
        MetadataIndexDto metadataIndexDto = buildMetadataIndexDto(queryResult, metadata4RefsInBoForPage, pageSize, pageIndex, metadata4RefInBo.size());
        // 分页
        return metadataIndexDto;
    }
    public MetadataIndexDto getUnionMetadataList(String text, String absolutePath, List<String> typeList, int pageSize, int pageIndex) {
        // 本地bo中元数据
        List<Metadata4Ref> metadata4RefInBo = getMetadata4RefListInBo(null, metadataProjectCoreService.getProjPath(absolutePath), typeList);
        MetadataProject metadataProject = getMetadataProjInfo(absolutePath);
        // 数据库中元数据
        List<Metadata4Ref> metadata4RefInDB = getMetadata4RefListByPostfixList(typeList, metadataProject);

        // 本地和数据库中元数据重复时，以本地BO中的为准
        List<Metadata4Ref> metadata4RefList = integrateMatadata(text, metadata4RefInBo, metadata4RefInDB);

        // 分页
        return buildMetadataIndexDto(pageSize, pageIndex, metadata4RefList);
    }
    /**
     * 根据条件分页获取数据库中的元数据引用列表
     *
     * @param text
     * @param postfixList
     * @param metadataProject
     * @param pageSize
     * @param pageIndex
     * @return
     */
    public Metadata4RefPageQueryResult getMetadata4RefListInDB(String text, String bizobjectID, int localMdCount, int localMdPageCount, List<String> postfixList, MetadataProject metadataProject, int pageSize, int pageIndex) {
        List<String> typeList = getTypeListForDB(postfixList);
        // 不支持生成型引用运行时
        if (Objects.isNull(metadataProject) || ProcessMode.generation == metadataProject.getMetadataPackageInfo().getProcessMode()) {
            return new Metadata4RefPageQueryResult();
        }

        // 查询mdpkg和idp数据
        Metadata4RefPageQueryParam metadata4RefQueryParam = new Metadata4RefPageQueryParam();
        metadata4RefQueryParam.setMetadataScopeEnum(MetadataScopeEnum.RUNTIME);

        //默认仅查询元数据包内元数据和 推送元数据
        ArrayList<SourceTypeEnum> sourceTypeEnums = Lists.newArrayList(SourceTypeEnum.MDPKG, SourceTypeEnum.GENERATED);

        // 若配置需要查询运行时定制发布元数据
        if (ClassifierUtils.getDbIncludeGeneratedMetadata()) {
            sourceTypeEnums.add(SourceTypeEnum.CUSTOMIZED);
        }

        metadata4RefQueryParam.setSourceTypeEnumList(sourceTypeEnums);
        metadata4RefQueryParam.setMetadataTypeList(typeList);
        metadata4RefQueryParam.setPageSize(pageSize);
        metadata4RefQueryParam.setPageIndex(pageIndex);
        metadata4RefQueryParam.setKeyword(text);
        metadata4RefQueryParam.setLocalMdCount(localMdCount);
        metadata4RefQueryParam.setLocalMdPageCount(localMdPageCount);
        metadata4RefQueryParam.setBizobjectID(bizobjectID);
        Metadata4RefPageQueryResult result = getCustomizationService().getMetadataListByQueryParam(metadata4RefQueryParam);
        return result;
    }
    @Deprecated
    private MetadataIndexDto buildMetadataIndexDto(int pageSize, int pageIndex, List<Metadata4Ref> metadata4RefList) {
        List<MetadataIndexItemDto> pageList = pageMetadata4RefList(pageSize, pageIndex, metadata4RefList);
        MetadataIndexDto dto = new MetadataIndexDto();
        Page dtoPage = new Page();
        dtoPage.setPageIndex(pageIndex);
        dtoPage.setPageSize(pageSize);
        dtoPage.setTotal(metadata4RefList.size());
        dto.setPage(dtoPage);
        dto.setMetadataIndexItems(pageList);
        return dto;
    }
    /**
     * 构建元数据索引dto
     *
     * @param queryResult
     * @param metadata4RefsInBoForPage
     * @param pageSize
     * @param pageIndex
     * @param localMdCount
     * @return
     */
    private MetadataIndexDto buildMetadataIndexDto(Metadata4RefPageQueryResult queryResult, List<Metadata4Ref> metadata4RefsInBoForPage, int pageSize, int pageIndex, int localMdCount) {
        MetadataIndexDto dto = new MetadataIndexDto();
        Page dtoPage = new Page();
        dtoPage.setPageIndex(pageIndex);
        dtoPage.setPageSize(pageSize);
        dtoPage.setTotal(queryResult.getTotal() + localMdCount);
        dto.setPage(dtoPage);
        List<MetadataIndexItemDto> metadataIndexItems = new ArrayList<>();
        metadata4RefsInBoForPage.addAll(queryResult.getList());
        metadata4RefsInBoForPage.forEach(metadata4Ref -> {
                    metadataIndexItems.add(new MetadataIndexItemDto(metadata4Ref));
                }
        );
        dto.setMetadataIndexItems(metadataIndexItems);
        return dto;
    }

    /**
     * 获取最近使用的元数据信息列表
     * @param absolutePath
     * @param typeList
     * @return
     */
    public List<MetadataIndexItemDto> getRecentMdUseList(String appId,String absolutePath, List<String> typeList) {

        // 运行时absolutePath为null,使用前端入参appId
        String sourceType = null;
        if(StringUtils.hasText(absolutePath)){
            GspProject gspProjectInfo = new GspProjectCoreService().getGspProjectInfo(absolutePath);
            appId = gspProjectInfo.getAppCode();
        }else{
            sourceType = SourceType.db.toString();
        }

        // 获取最近引用过的元数据列表
        List<GspMdRecentUse> recnetMdUseList = getMdRecentUseService().getRecnetMdUseList(appId,sourceType);
        List<MetadataIndexItemDto> metadataIndexItemDtoList = new ArrayList<>();
        if(CollectionUtils.isEmpty(recnetMdUseList)) {
            return metadataIndexItemDtoList;
        }
        // 获取当前操作需要的元数据类型
        List<String> typeListForDB = getTypeListForDB(typeList);
        if(!CollectionUtils.isEmpty(typeListForDB)){
            recnetMdUseList = recnetMdUseList.stream().filter(opInfo -> typeListForDB.contains(opInfo.getMdType())).collect(Collectors.toList());
        }
        // 获取列表，生成型只能引用生成型和非运行时元数据，解析型可以引用生成型和解析型
        boolean isGenerationFlag = false;
        if(StringUtils.hasText(absolutePath)){
            String projPath = metadataProjectCoreService.getProjPath(absolutePath);
            isGenerationFlag = isGenerationProject(projPath);
        }

        List<GspMdRecentUse> invalidList = new ArrayList<>();
        for (GspMdRecentUse mdop : recnetMdUseList) {
            Metadata4Ref metadata4Ref = null;
            try {

                if (SourceType.local.toString().equals(mdop.getSourceType())) {
                    String metadataAbsolutePath = ManagerUtils.getAbsolutePath(mdop.getMdPath());
                    if (isGenerationFlag && !isGenerationProject(metadataProjectCoreService.getProjPath(metadataAbsolutePath))) {
                        continue;
                    }
                    GspMetadata metadata = getMetadataWithoutContent(metadataAbsolutePath);
                    metadata4Ref = new Metadata4Ref(new MetadataPackageHeader(), new ServiceUnitInfo(), metadata);
                } else if (!isGenerationFlag) {
                    metadata4Ref = getMetadata4RefById(mdop.getMdId());
                    if (Objects.nonNull(metadata4Ref)) {
                        metadata4Ref.getMetadata().setRelativePath(null);
                    }
                }
            } catch (Exception e) {
                invalidList.add(mdop);
            }
            if(Objects.nonNull(metadata4Ref)) {
                metadataIndexItemDtoList.add(new MetadataIndexItemDto(metadata4Ref));
            }
        }
        // 如果存在失效数据，则删除记录
        if(!CollectionUtils.isEmpty(invalidList)) {
            getMdRecentUseService().deleteInBatch(invalidList);
        }
        // 去重，如果同一个元数据分别存在db和local类型的两个数据则保留local的
        deleteDuplicateData(metadataIndexItemDtoList);
        return metadataIndexItemDtoList;
    }

    /**
     * 删除重复数据
     *
     * @param metadataIndexItemDtoList
     */
    private void deleteDuplicateData(List<MetadataIndexItemDto> metadataIndexItemDtoList) {
        if (CollectionUtils.isEmpty(metadataIndexItemDtoList)) {
            return;
        }
        List<String> localMdIdList = metadataIndexItemDtoList.stream().filter(dto -> !StringUtils.isEmpty(dto.getRelativePath())).map(localdata -> localdata.getId()).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(localMdIdList)) {
            return;
        }
        List<MetadataIndexItemDto> dbList = metadataIndexItemDtoList.stream().filter(dto -> StringUtils.isEmpty(dto.getRelativePath())).collect(Collectors.toList());
        List<MetadataIndexItemDto> duplicatedataList = dbList.stream().filter(dbdata -> localMdIdList.contains(dbdata.getId())).collect(Collectors.toList());
        metadataIndexItemDtoList.removeAll(duplicatedataList);
    }

    /**
     * 整合BO和DB中的元数据
     *
     * @param metadata4RefInBo
     * @param metadata4RefInDB
     * @return
     */
    private List<Metadata4Ref> integrateMatadata(String text, List<Metadata4Ref> metadata4RefInBo, List<Metadata4Ref> metadata4RefInDB) {

        // 按照查询内容进行过滤
        metadata4RefInBo = metadata4RefInBo.stream().filter(mdInbo -> isValidMd(mdInbo, text)).collect(Collectors.toList());
        metadata4RefInDB = metadata4RefInDB.stream().filter(mdIndb -> isValidMd(mdIndb, text)).collect(Collectors.toList());

        if (!CollectionUtils.isEmpty(metadata4RefInBo) && !CollectionUtils.isEmpty(metadata4RefInDB)) {
            MetadataHeader headerInBo = metadata4RefInBo.get(0).getMetadata().getHeader();
            // 过滤数据库中与bo中相同的元数据
            metadata4RefInDB = metadata4RefInDB.stream().filter(mdIndb -> !headerInBo.getBizobjectID().equals(mdIndb.getMetadata().getHeader().getBizobjectID())).collect(Collectors.toList());
        }
        List<Metadata4Ref> metadata4RefList = new ArrayList<>();
        metadata4RefList.addAll(metadata4RefInBo);
        metadata4RefList.addAll(metadata4RefInDB);
        return metadata4RefList;
    }

    public List<MetadataIndexItemDto> pageMetadata4RefList(int pageSize, int pageIndex, List<Metadata4Ref> metadata4RefList) {
        List<MetadataIndexItemDto> metadataIndexItemDtoList = new ArrayList<>();

        int count = 0;
        int startIndex = (pageIndex - 1) * pageSize;
        int max = pageSize * pageIndex;
        for (int i = startIndex; i < metadata4RefList.size(); i++) {
            if (count >= max) {
                break;
            }
            count++;
            Metadata4Ref metadata4Ref = metadata4RefList.get(i);
            metadataIndexItemDtoList.add(new MetadataIndexItemDto(metadata4Ref));
        }

        return metadataIndexItemDtoList;
    }


    /**
     * 检查是否符合查询条件
     *
     * @param metadata4Ref
     * @param text
     * @return
     */
    private boolean isValidMd(Metadata4Ref metadata4Ref, String text) {

        if (StringUtils.isEmpty(text)) {
            return true;
        }
        return isMath(metadata4Ref.getMetadata().getHeader().getCode(), text)
                || isMath(metadata4Ref.getMetadata().getHeader().getName(), text)
                || Objects.nonNull(metadata4Ref.getPackageHeader()) && isMath(metadata4Ref.getPackageHeader().getName(), text);
    }


    public Metadata4RefDto pickMetadataIndex(int scopeType, String absolutePath, MetadataIndexItemDto metadataIndexItemDto, boolean isNeedMdDto, String packagePath, String mavenPath) {
        Metadata4Ref result;
        switch (scopeType) {
            case 1:
                result = pickLocalMdIndex(absolutePath, metadataIndexItemDto, isNeedMdDto, packagePath);
                break;
            // 远程maven中的元数据包
            case 2:
                result = pickRemoteMdIndex(absolutePath, metadataIndexItemDto, isNeedMdDto, packagePath, mavenPath);
                break;
            // 已引用的元数据包
            case 3:
                result = pickRefedMdIndex(absolutePath, metadataIndexItemDto, isNeedMdDto, packagePath, mavenPath);
                break;
            // 数据库中的元数据
            case 4:
                result = pickDBMdIndex(absolutePath, metadataIndexItemDto, isNeedMdDto);
                break;
            default:
                throw new IllegalArgumentException("Scope is invalid.");
        }
        if (result == null) {
            return null;
        }
        MetadataDto metadataDto = MetadataDtoConverter.asDto(result.getMetadata());
        Metadata4RefDto dto = new Metadata4RefDto();
        dto.setPackageHeader(result.getPackageHeader());
        if (scopeType == 4 && ((Metadata4RefForDB) result).isAcrossSU) {
            dto.setServiceUnitInfo(result.getServiceUnitInfo());
            dto.setIsAcrossSU(true);
        }
        dto.setMetadata(metadataDto);
        return dto;
    }

    public Metadata4RefDto pickMetadata(String absolutePath, MetadataIndexItemDto metadataIndexItemDto) {
        Metadata4Ref result = null;
        SourceType sourceTypeEnum = SourceType.local;
        String relativePath = metadataIndexItemDto.getRelativePath();
        String mdPath = relativePath;
        boolean isAcrossSU = false;
        // 如果relativePath为空，则是从数据库中获取
        if (StringUtils.isEmpty(relativePath)) {
            result = pickDBMdIndex(absolutePath, metadataIndexItemDto, true);
            sourceTypeEnum = SourceType.db;
            isAcrossSU = ((Metadata4RefForDB)result).isAcrossSU;
        } else {
            String metadataRelativePath = Paths.get(relativePath).resolve(metadataIndexItemDto.getFileName()).toString();
            String metadataAbsolutePath = ManagerUtils.getAbsolutePath(metadataRelativePath);
            GspMetadata gspMetadata = loadMetadataInApp(metadataAbsolutePath, absolutePath);
            if (Objects.nonNull(gspMetadata)) {
                gspMetadata.setRelativePath(ManagerUtils.getRelativePath(gspMetadata.getRelativePath()));
                mdPath = Utils.handlePath(metadataRelativePath);
                GspProject metadataGspProjectInfo = gspProjectCoreService.getGspProjectInfo(metadataAbsolutePath);
                result = new Metadata4Ref(new MetadataPackageHeader(), new ServiceUnitInfo(metadataGspProjectInfo.getAppCode(),metadataGspProjectInfo.getServiceUnitCode()), gspMetadata);
                if (!inWhiteList(result.getServiceUnitInfo().getAppCode(), result.getServiceUnitInfo().getServiceUnitCode())) {
                    GspProject gspProject = gspProjectCoreService.getGspProjectInfo(absolutePath);
                    if (!gspProject.getServiceUnitCode().equalsIgnoreCase(result.getServiceUnitInfo().getServiceUnitCode())) {
                        isAcrossSU = true;
                    }
                }
            }
        }
        if (Objects.isNull(result)) {
            return null;
        }
        GspMetadata metadata = result.getMetadata();
        // 元数据名称国际化
        metadata.getHeader().setI18nName(RuntimeContext.getLanguage());
        MetadataDto metadataDto = MetadataDtoConverter.asDto(metadata);
        Metadata4RefDto dto = new Metadata4RefDto();
        dto.setPackageHeader(result.getPackageHeader());
        if (isAcrossSU) {
            dto.setServiceUnitInfo(result.getServiceUnitInfo());
            dto.setIsAcrossSU(true);
        }
        dto.setMetadata(metadataDto);
        // 获取当前工程的appcode
        GspProject gspProjectInfo = new GspProjectCoreService().getGspProjectInfo(absolutePath);
        getMdRecentUseService().saveMdRecentUse(metadata.getHeader().getId(),
                StringUtils.isEmpty(mdPath) ? metadata.getHeader().getFileName() : mdPath,
                gspProjectInfo.getAppCode(), sourceTypeEnum.toString(),metadata.getHeader().getType());
        return dto;
    }

    public String getIndexServerStatus(String ip, String port) {
        final String testStatusWebapiIndexServer = IndexServerManager.getInstance().getTestStatusWebapiOfIndexServer(ip, port);
        return RestTemplateService.instance.getStatusByGet(testStatusWebapiIndexServer);
    }

    public void buildMetadataRef(GspMetadata metadata) {
        //构造元数据依赖关系
        IMetadataReferenceManager refManager = ReferenceManagerHelper.getInstance().getManager(metadata.getHeader().getType());
        if (refManager != null) {
            List<MetadataReference> refsCollection = refManager.getConstraint(metadata);
            metadata.setRefs(refsCollection);
        }
    }

    private Metadata4Ref pickRefedMdIndex(String currentPath, MetadataIndexItemDto metadataIndexItemDto, boolean isNeedMdDto, String packagePath, String mavenPath) {
        validateRemoteMdIndex(metadataIndexItemDto);
        MetadataProject metadataProject = getMetadataProjInfo(currentPath);
        Utils.checkNPE(metadataProject, "Path is invalid project folder:" + currentPath);

        String groupId = metadataIndexItemDto.getRepoPkg().get(0).getGroupId();
        String artifactId = metadataIndexItemDto.getRepoPkg().get(0).getArtifactId();
        String version = metadataIndexItemDto.getRepoPkg().get(0).getVersion();
        String metadataPackageName = fileService.getFileNameWithoutExtension(metadataIndexItemDto.getMdPkgName());

        MavenPackageRefs ref = new MavenPackageRefs();
        ref.setGroupId(groupId);
        ref.setArtifactId(artifactId);
        ref.setVersion(version);
        boolean installFlag = packageCoreService.getInstallFlag(ref, false, mavenPath, packagePath);
        if (installFlag) {
            try {
                packageCoreService.installMdpkg(groupId, artifactId, version, currentPath, true,
                        mavenPath, packagePath, metadataPackageName);
            } catch (IOException e) {
                throw new LcmMavenDevException(e, ErrorCodes.ECP_MAVEN_DEV_0004, groupId, artifactId, version);
            }
        }

        Metadata4Ref metadata = null;
        if (isNeedMdDto) {
            String metadataPackagePath = fileService.getCombinePath(mavenPath, groupId + '-' + artifactId + '-' + version);
            metadata = getMetadataFromPackage(metadataIndexItemDto.getMdPkgName(), metadataPackagePath, metadataIndexItemDto.getId());
            Utils.checkNPE(metadata, metadataPackagePath + "中的原数据包" + metadataIndexItemDto.getMdPkgName() + "不包含此元数据：" + metadataIndexItemDto.getId());
        }

        return metadata;
    }

    private Metadata4Ref pickRemoteMdIndex(String currentPath, MetadataIndexItemDto metadataIndexItemDto, boolean isNeedMdDto, String packagePath, String mavenPath) {
        validateRemoteMdIndex(metadataIndexItemDto);
        MetadataProject metadataProject = getMetadataProjInfo(currentPath);
        Utils.checkNPE(metadataProject, "Path is invalid project folder:" + currentPath);

        String groupId = metadataIndexItemDto.getRepoPkg().get(0).getGroupId();
        String artifactId = metadataIndexItemDto.getRepoPkg().get(0).getArtifactId();
        String version = metadataIndexItemDto.getRepoPkg().get(0).getVersion();
        String metadataPackageName = fileService.getFileNameWithoutExtension(metadataIndexItemDto.getMdPkgName());

        MavenPackageRefs ref = new MavenPackageRefs();
        ref.setGroupId(groupId);
        ref.setArtifactId(artifactId);
        ref.setVersion(version);
        ref.setMetadataPackageName(metadataPackageName);

        // 安装的包是生成型的才需要安装jar
        boolean isGenerationFlag = metadataIndexItemDto.getProcessMode() == null || metadataIndexItemDto.getProcessMode().isEmpty() || metadataIndexItemDto.getProcessMode().equals(ProcessMode.generation.toString());
        boolean installFlag = packageCoreService.getInstallFlag(ref, true, mavenPath, packagePath);
        if (installFlag) {
            try {
                packageCoreService.installMdpkg(groupId, artifactId, version, currentPath,
                        isGenerationFlag, mavenPath, packagePath, metadataPackageName);
            } catch (IOException e) {
                throw new LcmMavenDevException(e, ErrorCodes.ECP_MAVEN_DEV_0004, groupId, artifactId, version);
            }
        }

        Metadata4Ref metadata = null;
        if (isNeedMdDto) {
            String metadataPackagePath = fileService.getCombinePath(mavenPath, groupId + '-' + artifactId + '-' + version);
            metadata = getMetadataFromPackage(metadataIndexItemDto.getMdPkgName(), metadataPackagePath, metadataIndexItemDto.getId());
            Utils.checkNPE(metadata, metadataPackagePath + "中的原数据包" + metadataIndexItemDto.getMdPkgName() + "不包含此元数据：" + metadataIndexItemDto.getId());
        }

        MetadataPackageHeader metadataPackageHeader = new MetadataPackageHeader();
        metadataPackageHeader.setName(metadataPackageName);
        metadataPackageHeader.setVersion(new MetadataPackageVersion("1.0.0"));
        ProcessMode processMode = isGenerationFlag ? ProcessMode.generation : ProcessMode.interpretation;
        metadataPackageHeader.setProcessMode(processMode);
        metadataProjectCoreService.updateRefs(currentPath, metadataProject, metadataPackageHeader);
        metadataProjectCoreService.updateMavenRefs(currentPath, metadataProject, ref);

        return metadata;
    }

    private void validateRemoteMdIndex(MetadataIndexItemDto metadataIndexItemDto) {
        if (metadataIndexItemDto.getRepoPkg() == null || metadataIndexItemDto.getRepoPkg().size() < 1) {
            throw new IllegalArgumentException("未指定仓库包。");
        }
    }

    private Metadata4Ref pickLocalMdIndex(String currentPath, MetadataIndexItemDto metadataIndexItemDto, boolean isNeedMdDto, String packagePath) {
        String mdPkgName = metadataIndexItemDto.getMdPkgName();
        String mdPkgFullName = mdPkgName + Utils.getMetadataPackageExtension();
        // 获取工程信息
        MetadataProject metadataProject = getMetadataProjInfo(currentPath);
        Utils.checkNPE(metadataProject, "Path is invalid project folder:" + currentPath);
        // 本地是否存在
        if (!MetadataIndexCacheService.getInstance().isExistInLocalPackages(mdPkgName)) {
            throw new IllegalArgumentException("Local package: " + mdPkgName + " not exists");
        }

        Metadata4Ref metadata = null;
        if (isNeedMdDto) {
            String metadataPackagePath = fileService.getCombinePath(packagePath, mdPkgFullName);
            metadata = getMetadataFromPackage(mdPkgFullName, metadataPackagePath, metadataIndexItemDto.getId());
            Utils.checkNPE(metadata, metadataPackagePath + "中的元数据包" + metadataIndexItemDto.getMdPkgName() + "不包含此元数据：" + metadataIndexItemDto.getId());
        }

        MetadataPackageHeader metadataPackageHeader = new MetadataPackageHeader();
        metadataPackageHeader.setName(mdPkgName);
        metadataPackageHeader.setVersion(new MetadataPackageVersion("1.0.0"));
        metadataProjectCoreService.updateRefs(currentPath, metadataProject, metadataPackageHeader);

        return metadata;
    }

    private Metadata4RefForDB pickDBMdIndex(String currentPath, MetadataIndexItemDto metadataIndexItemDto, boolean isNeedMdDto) {
        // 获取工程信息
        MetadataProject metadataProject = getMetadataProjInfo(currentPath);
        Utils.checkNPE(metadataProject, "Path is invalid project folder:" + currentPath);

        Metadata4RefForDB metadata4Ref = new Metadata4RefForDB();
        if (isNeedMdDto) {
            if (Objects.isNull(metadataIndexItemDto.getMdPkgName())) {
                // 查询idp元数据 或运行时定制元数据 信息
                MetadataCustomizationFilter metadataCustomizationFilter = new MetadataCustomizationFilter();
                metadataCustomizationFilter.setMetadataId(metadataIndexItemDto.getId());
                metadataCustomizationFilter.setIsI18n(false);
                GspMetadata gspMetadata = getMetadataRTService().getMetadata(metadataCustomizationFilter);
                Utils.checkNPE(gspMetadata, "数据库中不存在此元数据: " + metadataIndexItemDto.getId());
                if (Objects.isNull(gspMetadata.getHeader().getFileName())) {
                    gspMetadata.getHeader().setFileName(gspMetadata.getHeader().getName());
                }

                // 尝试获取运行时定制元数据对应基础元数据及其所属元数据包
                // 若结果为null,可能为IDP元数据或运行时定制元数据找不到基础元数据
                Metadata4Ref pkgMetadata = getBasicPkgMetadataByExtMdId(gspMetadata.getHeader().getId(), gspMetadata.getHeader().getCertId());
                if (pkgMetadata != null && pkgMetadata.getPackageHeader() != null) {
                    metadataIndexItemDto.setMdPkgName(pkgMetadata.getPackageHeader().getName());
                    metadataIndexItemDto.setProcessMode(ProcessMode.interpretation.toString());
                }

                metadata4Ref.setMetadata(gspMetadata);
                metadata4Ref.setPackageHeader(new MetadataPackageHeader(gspMetadata.getHeader().getName(), null, null, null));
            } else {
                // 查询mdpkg元数据信息
                Metadata4Ref re = getMetadata4Ref(metadataIndexItemDto.getId());
                Utils.checkNPE(re, "数据库中不存在此元数据: " + metadataIndexItemDto.getId());
                metadata4Ref.setMetadata(re.getMetadata());
                metadata4Ref.setPackageHeader(re.getPackageHeader());
                // 白名单过滤：平台及产品部公共元数据不提示跨SU引用信息
                if (!inWhiteList(re.getServiceUnitInfo().getAppCode(), re.getServiceUnitInfo().getServiceUnitCode())) {
                    GspProject gspProject = gspProjectCoreService.getGspProjectInfo(currentPath);
                    if (!gspProject.getServiceUnitCode().equalsIgnoreCase(re.getServiceUnitInfo().getServiceUnitCode())) {
                        metadata4Ref.setAcrossSU(true);
                        metadata4Ref.setServiceUnitInfo(re.getServiceUnitInfo());
                    }
                }
            }
        } else if (Objects.isNull(metadataIndexItemDto.getMdPkgName())){
            // 不需要返回元数据信息时, 元数据不为包下元数据时需要判断其是否运行时定制元数据,若为运行时定制,则获取其包信息
            Metadata4Ref pkgMetadata = getBasicPkgMetadataByExtMdId(metadataIndexItemDto.getId(), null);
            if (pkgMetadata != null && pkgMetadata.getPackageHeader() != null) {
                metadataIndexItemDto.setMdPkgName(pkgMetadata.getPackageHeader().getName());
                metadataIndexItemDto.setProcessMode(ProcessMode.interpretation.toString());
            }
        }

        // 更新引用信息
        if (Objects.isNull(metadataIndexItemDto.getMdPkgName())) {
            ExternalInfo externalInfo = new ExternalInfo();
            externalInfo.setMetadataId(metadataIndexItemDto.getId());
            metadataProjectCoreService.updateIdpRefs(currentPath, metadataProject, externalInfo);
        } else {
            boolean isGenerationFlag = metadataIndexItemDto.getProcessMode() == null || metadataIndexItemDto.getProcessMode().isEmpty() || metadataIndexItemDto.getProcessMode().equals(ProcessMode.generation.toString());
            MetadataPackageHeader metadataPackageHeader = new MetadataPackageHeader();
            metadataPackageHeader.setName(metadataIndexItemDto.getMdPkgName());
            metadataPackageHeader.setVersion(new MetadataPackageVersion("1.0.0"));
            ProcessMode processMode = isGenerationFlag ? ProcessMode.generation : ProcessMode.interpretation;
            metadataPackageHeader.setProcessMode(processMode);
            metadataProjectCoreService.updateDbRefs(currentPath, metadataProject, metadataPackageHeader);
        }

        return metadata4Ref;
    }

    private boolean inWhiteList(String appCode, String suCode) {
        AcrossSUWhiteListConfiguration acrossSUWhiteListConfiguration = AcrossSUWhiteListUtils.getAcrossSUWhiteList();
        if (Objects.isNull(acrossSUWhiteListConfiguration)) {
            return false;
        }
        if (!CollectionUtils.isEmpty(acrossSUWhiteListConfiguration.getAppList())) {
            AcrossSUInfo re = acrossSUWhiteListConfiguration.getAppList().stream().filter(acrossSUInfo -> appCode.equalsIgnoreCase(acrossSUInfo.getCode())).findFirst().orElse(null);
            if (Objects.nonNull(re)) {
                return true;
            }
        }
        if (!CollectionUtils.isEmpty(acrossSUWhiteListConfiguration.getSuList())) {
            AcrossSUInfo re = acrossSUWhiteListConfiguration.getSuList().stream().filter(acrossSUInfo -> suCode.equalsIgnoreCase(acrossSUInfo.getCode())).findFirst().orElse(null);
            if (Objects.nonNull(re)) {
                return true;
            }
        }
        return false;
    }

    private List<MetadataIndexItemDto> buildIndexDtoFromMetadataInfoWithVersion(List<MetadataInfoWithVersion> versions) {
        if (versions.size() < 1) {
            return new ArrayList<>();
        }
        List<MetadataIndexItemDto> dtos = new ArrayList<>();
        versions.forEach(version -> {
            MetadataIndexItemDto indexDto = new MetadataIndexItemDto();
            indexDto.setId(version.getMetadataId());
            indexDto.setCode(version.getMetadataCode());
            indexDto.setName(version.getMetadataName());
            indexDto.setNameSpace(version.getMetadataNamespace());
            indexDto.setType(version.getMetadataType());
            indexDto.setBizobjectID(version.getMdBizobjectId());
            indexDto.setLanguage(version.getMetadataLanguage());
            indexDto.setIsTranslating(version.getMetadataIsTranslating() != null && "true".equals(version.getMetadataIsTranslating()));
            indexDto.setMdPkgName(version.getPackageCode() + ".mdpkg");
            List<MetadataIndexRepoItemDto> metadataIndexRepoItemDtoList = new ArrayList<>();
            version.getMavenInfos().forEach(maveninfo -> {
                MetadataIndexRepoItemDto metadataIndexRepoItemDto = new MetadataIndexRepoItemDto();
                metadataIndexRepoItemDto.setGroupId(maveninfo.getMavenPackageGroupId());
                metadataIndexRepoItemDto.setArtifactId(maveninfo.getMavenPackageArtifactId());
                metadataIndexRepoItemDto.setVersion("m" + maveninfo.getMavenPackageVersion());
                metadataIndexRepoItemDto.setUrl(maveninfo.getMavenPackageUrl());
                metadataIndexRepoItemDto.setProcessMode(ProcessMode.generation.toString());
                metadataIndexRepoItemDtoList.add(metadataIndexRepoItemDto);
            });
            if ((version.getMavenInfos() == null || version.getMavenInfos().size() < 1)) {
                indexDto.setRepoPkg(new ArrayList<>());
            } else {
                indexDto.setRepoPkg(metadataIndexRepoItemDtoList);
            }
            dtos.add(indexDto);
        });
        return dtos;
    }

    private List<MetadataIndexItemDto> buildIndexDtoFromMetadataInfoWithVersionWithProcessMode(List<MetadataInfoWithVersionWithProcessMode> versions) {
        if (versions.size() < 1) {
            return new ArrayList<>();
        }
        List<MetadataIndexItemDto> dtos = new ArrayList<>();
        versions.forEach(version -> {
            MetadataIndexItemDto indexDto = new MetadataIndexItemDto();
            indexDto.setId(version.getMetadataId());
            indexDto.setCode(version.getMetadataCode());
            indexDto.setName(version.getMetadataName());
            indexDto.setNameSpace(version.getMetadataNamespace());
            indexDto.setType(version.getMetadataType());
            indexDto.setBizobjectID(version.getMdBizobjectId());
            indexDto.setLanguage(version.getMetadataLanguage());
            indexDto.setIsTranslating(version.getMetadataIsTranslating() != null && "true".equals(version.getMetadataIsTranslating()));
            indexDto.setMdPkgName(version.getPackageCode() + ".mdpkg");
            indexDto.setProcessMode(version.getProcessMode());
            List<MetadataIndexRepoItemDto> metadataIndexRepoItemDtoList = new ArrayList<>();
            version.getMavenInfos().forEach(maveninfo -> {
                MetadataIndexRepoItemDto metadataIndexRepoItemDto = new MetadataIndexRepoItemDto();
                metadataIndexRepoItemDto.setGroupId(maveninfo.getMavenPackageGroupId());
                metadataIndexRepoItemDto.setArtifactId(maveninfo.getMavenPackageArtifactId());
                metadataIndexRepoItemDto.setVersion("m" + maveninfo.getMavenPackageVersion());
                metadataIndexRepoItemDto.setUrl(maveninfo.getMavenPackageUrl());
                metadataIndexRepoItemDto.setProcessMode(maveninfo.getProcessMode());
                metadataIndexRepoItemDtoList.add(metadataIndexRepoItemDto);
            });
            if ((version.getMavenInfos() == null || version.getMavenInfos().size() < 1)) {
                indexDto.setRepoPkg(new ArrayList<>());
            } else {
                indexDto.setRepoPkg(metadataIndexRepoItemDtoList);
            }
            dtos.add(indexDto);
        });
        return dtos;
    }

    private MetadataInfoFilter getMetadataInfoFilter(String text, List<String> typePostfixList, boolean page, int pageSize, int pageIndex, String selectedPackageSource, String projPath, boolean isFilterByRefs) {

        MetadataInfoFilter metadataInfoFilter = new MetadataInfoFilter();
        metadataInfoFilter.setCodeOrName(text);
        metadataInfoFilter.setPageable(page);
        metadataInfoFilter.setPageSize(pageSize);
        metadataInfoFilter.setPageIndex(pageIndex);
        // 检查类型是否正确
        List<String> metadataTypes = new ArrayList<>();
        if (typePostfixList != null && typePostfixList.size() > 0) {
            List<MetadataType> typeList = getMetadataTypeList();
            typeList.forEach(type -> {
                if (typePostfixList.contains(type.getPostfix().toLowerCase())) {
                    metadataTypes.add(type.getTypeCode().toLowerCase());
                }
            });
            metadataInfoFilter.setMetadataTypes(metadataTypes);
        }
        // packageSources
        List<String> packageSrouceList = new ArrayList<>();
        if (selectedPackageSource != null && !selectedPackageSource.isEmpty()) {
            MdpkgService mdpkgService = SpringBeanUtils.getBean(MdpkgService.class);
            List<PackageSourceDto> packageSourceDtoList = mdpkgService.getRepoList().getRepoList();
            if ("All".equals(selectedPackageSource)) {
                for (PackageSourceDto packageSourceDto : packageSourceDtoList) {
                    packageSrouceList.add(packageSourceDto.getSourceUrl());
                }
            } else {
                for (PackageSourceDto packageSourceDto : packageSourceDtoList) {
                    if (packageSourceDto.getId() != null) {
                        if (packageSourceDto.getId().equals(selectedPackageSource)) {
                            packageSrouceList.add(packageSourceDto.getSourceUrl());
                        }
                    }
                }
            }
            metadataInfoFilter.setPackageSources(getEntitySources(packageSrouceList));
        }

        // 获取自己的metadataCode
        MetadataProject projInfo = null;
        if (!(projPath == null || projPath.isEmpty())) {
            projInfo = getMetadataProjInfo(projPath);
            metadataInfoFilter.setPackageCodeExcluded(projInfo.getMetadataPackageInfo().getName());
        }

        // 获取MavenRefPackages
        List<MetadataMavenInfo> refsList = new ArrayList<>();
        if (projInfo != null && isFilterByRefs) {
            if (projInfo.getMavenPackageRefs() != null && projInfo.getMavenPackageRefs().size() > 0) {
                for (MavenPackageRefs ref : projInfo.getMavenPackageRefs()) {
                    MetadataMavenInfo packageRef = new MetadataMavenInfo();
                    packageRef.setMavenPackageGroupId(ref.getGroupId());
                    packageRef.setMavenPackageArtifactId(ref.getArtifactId());
                    packageRef.setMavenPackageVersion(ref.getVersion().substring(1));
                    refsList.add(packageRef);
                }
            }
        }
        metadataInfoFilter.setRefPackages(refsList);

        return metadataInfoFilter;
    }

    private MetadataInfoFilterWithProcessMode getMetadataInfoFilter(String text, List<String> typePostfixList, boolean page, int pageSize, int pageIndex, String selectedPackageSource, String projPath, boolean isFilterByRefs, ProcessMode processMode) {
        MetadataInfoFilterWithProcessMode metadataInfoFilterWithProcessMode = new MetadataInfoFilterWithProcessMode();
        metadataInfoFilterWithProcessMode.setCodeOrName(text);
        metadataInfoFilterWithProcessMode.setPageable(page);
        metadataInfoFilterWithProcessMode.setPageSize(pageSize);
        metadataInfoFilterWithProcessMode.setPageIndex(pageIndex);
        // 检查类型是否正确
        List<String> metadataTypes = new ArrayList<>();
        if (typePostfixList != null && typePostfixList.size() > 0) {
            List<MetadataType> typeList = getMetadataTypeList();
            typeList.forEach(type -> {
                if (typePostfixList.contains(type.getPostfix().toLowerCase())) {
                    metadataTypes.add(type.getTypeCode().toLowerCase());
                }
            });
            metadataInfoFilterWithProcessMode.setMetadataTypes(metadataTypes);
        }
        // packageSources
        List<String> packageSrouceList = new ArrayList<>();
        if (selectedPackageSource != null && !selectedPackageSource.isEmpty()) {
            MdpkgService mdpkgService = SpringBeanUtils.getBean(MdpkgService.class);
            List<PackageSourceDto> packageSourceDtoList = mdpkgService.getRepoList().getRepoList();
            if ("All".equals(selectedPackageSource)) {
                for (PackageSourceDto packageSourceDto : packageSourceDtoList) {
                    packageSrouceList.add(packageSourceDto.getSourceUrl());
                }
            } else {
                for (PackageSourceDto packageSourceDto : packageSourceDtoList) {
                    if (packageSourceDto.getId() != null) {
                        if (packageSourceDto.getId().equals(selectedPackageSource)) {
                            packageSrouceList.add(packageSourceDto.getSourceUrl());
                        }
                    }
                }
            }
            metadataInfoFilterWithProcessMode.setPackageSources(getEntitySources(packageSrouceList));
        }

        // 获取自己的metadataCode
        MetadataProject projInfo = null;
        if (!(projPath == null || projPath.isEmpty())) {
            projInfo = getMetadataProjInfo(projPath);
            metadataInfoFilterWithProcessMode.setPackageCodeExcluded(projInfo.getMetadataPackageInfo().getName());
        }

        // 获取MavenRefPackages
        List<MetadataMavenInfoWithProcessMode> refsList = new ArrayList<>();
        if (projInfo != null && isFilterByRefs) {
            if (projInfo.getMavenPackageRefs() != null && projInfo.getMavenPackageRefs().size() > 0) {
                for (MavenPackageRefs ref : projInfo.getMavenPackageRefs()) {
                    MetadataMavenInfoWithProcessMode packageRef = new MetadataMavenInfoWithProcessMode();
                    packageRef.setMavenPackageGroupId(ref.getGroupId());
                    packageRef.setMavenPackageArtifactId(ref.getArtifactId());
                    packageRef.setMavenPackageVersion(ref.getVersion().substring(1));
                    refsList.add(packageRef);
                }
            }
        }
        metadataInfoFilterWithProcessMode.setRefPackages(refsList);

        metadataInfoFilterWithProcessMode.setProcessMode(
                processMode.equals(ProcessMode.generation) && !MetadataRefConfigHelper.getInstance().isAllowInterpretationRefer() ?
                        ProcessMode.generation.toString() : "All");

        return metadataInfoFilterWithProcessMode;
    }

    private List<String> getEntitySources(List<String> packageSrouceList) {
        List<String> entitySources = new ArrayList<>();
        Map<String, List<String>> mavenSourceRule = MavenSourceRuleHelper.getInstance().getMavenSourceRuleMap();
        if (mavenSourceRule != null && mavenSourceRule.size() > 0) {
            for (String source : packageSrouceList) {
                String key = source.split("/")[source.split("/").length - 1];
                if (mavenSourceRule.containsKey(key)) {
                    entitySources.addAll(mavenSourceRule.get(key));
                } else {
                    entitySources.add(source);
                }
            }
        }
        return entitySources.stream().distinct().collect(Collectors.toList());
    }

    private boolean isPackMd(LocalMetadataIndexItem item, List<String> typeList, String text, String packageNameExcluded) {

        boolean isPack = false;
        if (typeList == null || typeList.contains(fileService.getExtension(item.getFileName().toLowerCase()))) {
            if (item.getMdPkgName().equals(packageNameExcluded)) {
                return false;
            }
            if (text == null || text.isEmpty()) {
                isPack = true;
            } else {
                if (isMath(item.getCode(), text)) {
                    isPack = true;
                } else if (isMath(item.getName(), text)) {
                    isPack = true;
                } else if (isMath(item.getMdPkgName(), text)) {
                    isPack = true;
                } else if (isMath(item.getNameSpace(), text)) {
                    isPack = true;
                }
            }
        }
        return isPack;
    }

    private MetadataIndexItemDto assemblyMetadataIndexItemDto(LocalMetadataIndexItem mdIndexDto) {
        MetadataIndexItemDto dto = new MetadataIndexItemDto();
        dto.setId(mdIndexDto.getId());
        dto.setName(mdIndexDto.getName());
        dto.setCode(mdIndexDto.getCode());
        dto.setFileName(mdIndexDto.getFileName());
        dto.setNameSpace(mdIndexDto.getNameSpace());
        dto.setMdPkgName(mdIndexDto.getMdPkgName());
        dto.setType(mdIndexDto.getType());
        dto.setRelativePath(mdIndexDto.getRelativePath());
        String processMode = mdIndexDto.getProcessMode() == null || mdIndexDto.getProcessMode().isEmpty() || mdIndexDto.getProcessMode().equals(ProcessMode.generation.toString()) ? ProcessMode.generation.toString() : ProcessMode.interpretation.toString();
        dto.setProcessMode(processMode);
        if (mdIndexDto.getRepoPkg() != null) {
            MetadataIndexRepoItemDto metadataIndexRepoItemDto = new MetadataIndexRepoItemDto();
            metadataIndexRepoItemDto.setGroupId(mdIndexDto.getRepoPkg().getGroupId());
            metadataIndexRepoItemDto.setArtifactId(mdIndexDto.getRepoPkg().getArtifactId());
            metadataIndexRepoItemDto.setVersion(mdIndexDto.getRepoPkg().getVersion());
            List<MetadataIndexRepoItemDto> list = new ArrayList<>();
            list.add(metadataIndexRepoItemDto);
            dto.setRepoPkg(list);
        }
        return dto;
    }

    private MetadataPackage getMetadataPackage(String defaultPackagePath, String absolutePath) {
        lock.lock();
        File file = new File(absolutePath);
        try(ZipFile zf = new ZipFile(file);
            InputStream in = new BufferedInputStream(new FileInputStream(absolutePath));
            ZipInputStream zin = new ZipInputStream(in, StandardCharsets.UTF_8)) {

            ZipEntry ze;
            StringBuilder sb = new StringBuilder();
            while ((ze = zin.getNextEntry()) != null) {
                try (BufferedReader br = new BufferedReader(
                        new InputStreamReader(zf.getInputStream(ze), StandardCharsets.UTF_8))) {
                    if (ze.toString().equals(Utils.getManifestFileName())) {
                        String line;
                        while ((line = br.readLine()) != null) {
                            sb.append(line);
                        }
                        break;
                    }
                } catch (IOException e) {
                    throw new IOException("读取元数据失败", e);
                }
            }
            ObjectMapper objectMapper = Utils.getMapper();
            return objectMapper.readValue(sb.toString(), MetadataPackage.class);
        } catch (IOException e) {
            throw new LcmParseDevException(e, ErrorCodes.ECP_PARSE_DEV_0001, absolutePath);
        } finally {
            lock.unlock();
        }
    }

    public boolean validateRepeatName(String absolutePath, String fileName) {
        String combinePath = fileService.getCombinePath(absolutePath, fileName);
        return !isMetadataExist(combinePath);
    }

    public List<GspMetadata> getMetadataByFilter(String absolutePath, MetadataFilter metadataFilter) {
        List<String> typeList = new ArrayList<>();
        if (metadataFilter.getMetadataPostfix() != null && !metadataFilter.getMetadataPostfix().isEmpty()) {
            String[] types = metadataFilter.getMetadataPostfix().split(",");
            typeList = Arrays.asList(types);
        }
        // TODO 加上各元数据自己的过滤器
        return getMetadataList(absolutePath, typeList);
    }

    public List<MetadataDto> getMetadataListInSu(String projPath, List<String> metadataTypes) {

        List<String> projectsInSu = metadataProjectCoreService.getProjectsInSuByProjPath(projPath);

        // 获取列表，生成型只能引用生成型，解析型可以引用生成型和解析型
        boolean isGenerationFlag = isGenerationProject(projPath);
        List<MetadataDto> metadataList = new ArrayList<>();
        projectsInSu.forEach(project -> {
            MetadataProject metadataProjInfoInBo = metadataProjectCoreService.getMetadataProjInfo(project);
            if (isGenerationFlag && !MetadataRefConfigHelper.getInstance().isAllowInterpretationRefer()) {
                boolean isEachProjectGenerationFlag = metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode() == null || metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode().equals(ProcessMode.generation);
                if (!isEachProjectGenerationFlag) {
                    return;
                }
            }

            String metadataProjPath = project + File.separator + Utils.getMetadataProjPath();
            List<GspMetadata> result = getMetadataList(metadataProjPath, metadataTypes);
            for (GspMetadata metadata : result) {
                MetadataDto metadataDto = MetadataDtoConverter.asDto(metadata);
                metadataDto.setProjectName(new File(project).getName());
                metadataDto.setProcessMode(metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode() == null ? ProcessMode.generation.toString() : metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode().toString());
                metadataList.add(metadataDto);
            }
        });
        return metadataList;
    }
    public GspMetadata loadMetadataInApp(String absoluteMetadataPath, String absoluteProjPath) {
        absoluteProjPath = metadataProjectCoreService.getProjPath(absoluteProjPath);
        GspProject currentGspProjectInfo = gspProjectCoreService.getGspProjectInfo(absoluteProjPath);
        GspProject metadataGspProjectInfo = gspProjectCoreService.getGspProjectInfo(absoluteMetadataPath);
        if (!currentGspProjectInfo.getMetadataPackageName().equals(metadataGspProjectInfo.getMetadataPackageName())) {
            updateAppRef(metadataGspProjectInfo, absoluteMetadataPath, absoluteProjPath);
        }
        File file = new File(absoluteMetadataPath);
        return getI18nMetadata(file.getName(), file.getParent(), RuntimeContext.getLanguage());
    }

    public void updateAppRef(GspProject gspProjInfo, String metadataFullPath, String currentProjPath) {
        String projectPath = Paths.get("../../../..")
                .resolve(gspProjInfo.getAppCode())
                .resolve(gspProjInfo.getServiceUnitCode())
                .resolve(gspProjInfo.getBizobjectCode())
                .resolve(gspProjInfo.getMetadataProjectName().toLowerCase())
                .toString().replace("\\", "/");
        updateRef(gspProjInfo, metadataFullPath, currentProjPath, projectPath);
    }

    public Metadata4Ref getMetadata4Ref(String metadataId) {
        return getCustomizationRtServerService().getMetadata4Ref(metadataId);
    }

    public List<MetadataIndexItemDto> getDBMetadataList(String text, String absolutePath, List<String> typeList, boolean page, int pageSize, int pageIndex, MetadataProject metadataProject) {
        // 获取元数据
        List<Metadata4Ref> metadata4RefList = getMetadata4RefListByTypeList(typeList, metadataProject);
        List<MetadataIndexItemDto> metadataIndexItemDtoList = new ArrayList<>();
        if (io.iec.edp.caf.commons.utils.CollectionUtils.isEmpty(metadata4RefList)) {
            return metadataIndexItemDtoList;
        }
        // 按关键字过滤及分页处理
        String packageNameExcluded = metadataProject.getMetadataPackageInfo().getName();
        if (!page) {
            for (Metadata4Ref metadata4Ref : metadata4RefList) {
                if (isValidMd(metadata4Ref, text, packageNameExcluded)) {
                    metadataIndexItemDtoList.add(new MetadataIndexItemDto(metadata4Ref));
                }
            }
        } else {
            int count = 0;
            int skip = pageIndex * pageSize;
            int max = pageSize + skip;
            for (Metadata4Ref metadata4Ref : metadata4RefList) {
                if (count >= max) {
                    break;
                }
                if (isValidMd(metadata4Ref, text, packageNameExcluded)) {
                    count++;
                    if (count <= skip) {
                        continue;
                    }
                    metadataIndexItemDtoList.add(new MetadataIndexItemDto(metadata4Ref));
                }
            }
        }
        return metadataIndexItemDtoList;
    }

    /**
     * 根据元数据类型获取工程下符合条件元数据列表
     * @param typeList 元数据类型条件
     * @param metadataProject 元数据工程
     * @return 工程下符合类型条件的元数据列表
     */
    public List<Metadata4Ref> getMetadata4RefListByTypeList(List<String> typeList, MetadataProject metadataProject) {
        if (Objects.isNull(metadataProject)) {
            return new ArrayList<>();
        }
        // 不支持生成型引用运行时
        if (ProcessMode.generation == metadataProject.getMetadataPackageInfo().getProcessMode()) {
            return new ArrayList<>();
        }
        // 查询mdpkg和idp数据
        Metadata4RefQueryParam metadata4RefQueryParam = new Metadata4RefQueryParam();
        metadata4RefQueryParam.setMetadataScopeEnum(MetadataScopeEnum.RUNTIME);

        //默认仅查询元数据包内元数据和 推送元数据
        ArrayList<SourceTypeEnum> sourceTypeEnums = Lists.newArrayList(SourceTypeEnum.MDPKG, SourceTypeEnum.GENERATED);

        // 若配置需要查询运行时定制发布元数据
        if (ClassifierUtils.getDbIncludeGeneratedMetadata()) {
            sourceTypeEnums.add(SourceTypeEnum.CUSTOMIZED);
        }

        metadata4RefQueryParam.setSourceTypeEnumList(sourceTypeEnums);
        metadata4RefQueryParam.setMetadataTypeList(typeList);
        List<Metadata4Ref> metadata4RefList = getCustomizationService().getMetadataList(metadata4RefQueryParam);
        if (Objects.isNull(metadata4RefList)) {
            metadata4RefList = new ArrayList<>();
        }
        return metadata4RefList;
    }

    public Metadata4Ref getBasicPkgMetadataByExtMdId(String metadataId, String certId) {
        return getCustomizationService().getBasicPkgMetadataByExtMdId(metadataId, certId);
    }

    public Metadata4Ref getMetadata4RefById(String metadataId) {
        return getCustomizationService().getMetadata4RefById(metadataId);
    }

    /**
     * 检查是否符合查询条件
     *
     * @param metadata4Ref
     * @param text
     * @param packageNameExcluded
     * @return
     */
    private boolean isValidMd(Metadata4Ref metadata4Ref, String text, String packageNameExcluded) {
        // 排除自己
        if (Objects.nonNull(metadata4Ref) &&
                Objects.nonNull(metadata4Ref.getPackageHeader()) &&
                Objects.nonNull(metadata4Ref.getPackageHeader().getName()) &&
                metadata4Ref.getPackageHeader().getName().equals(packageNameExcluded)) {
            return false;
        }
        if (Objects.isNull(text) || text.isEmpty()) {
            return true;
        }
        if (isMath(metadata4Ref.getMetadata().getHeader().getCode(), text)) {
            return true;
        }
        if (isMath(metadata4Ref.getMetadata().getHeader().getName(), text)) {
            return true;
        }
        if (Objects.nonNull(metadata4Ref.getPackageHeader()) && isMath(metadata4Ref.getPackageHeader().getName(), text)) {
            return true;
        }
        return false;
    }

    private boolean isMath(String content, String text) {
        if (Objects.isNull(content) || content.isEmpty()) {
            return false;
        }
        return content.toLowerCase().contains(text.toLowerCase());
    }
}
